Archive

Archive for the ‘WPF’ Category

WPF TabControl transition effects with Transitionals

May 13th, 2008

Transitionals is a WPF framework that allows you to integrate nice transition effects into your WPF application with very little effort. It’s gone live a few days ago on CodePlex and definitely worth checking out:

http://www.codeplex.com/transitionals

 

I’ve downloaded the library today in order to incorporate a little eye candy into a prototype I’m doing. However, what I wanted to do was adding transition effects on a tab control, which is currently not supported out of the box by the framework:

Currently Transitionals ships with only two controls out of the box […]. Other controls, like a Tab control for example, could also be created. We encourage the community to come up with other common navigation and presentation scenarios that can leverage transitions.

This sounded like a lot of work, but luckily, it wasn’t: TabControl provides a ContentTemplate property which can be bound to a data template. This is were I put a TransitionElement control and bound it to the current content of the tab control:

<DataTemplate x:Key="TabTemplate">
  <t:TransitionElement Content="{Binding}">
    <!-- some more stuff -->
  </t:TransitionElement>
</DataTemplate>

<!-- tab control with content template -->
<TabControl ContentTemplate="{StaticResource TabTemplate}" />

 

These bindings take care of everything – a tab switch changes the content of the TransitionElement, which triggers a transition animation. All that was left to do was configuring a transition effect and adding some content to the tab control. Here’s the complete listing that uses a 3D rotation effect:

 

<Grid>
  <Grid.Resources>

    <!-- the data template binds the content to a transition element -->
    <DataTemplate x:Key="TabTemplate">
      <t:TransitionElement Content="{Binding}">
        <!-- rotate tab contents -->
        <t:TransitionElement.Transition>
          <trans:RotateTransition Duration="0:0:1.500"
                                  Angle="90" />
        </t:TransitionElement.Transition>
      </t:TransitionElement>
    </DataTemplate>

  </Grid.Resources>


  <TabControl ContentTemplate="{StaticResource TabTemplate}">

    <TabItem Header="First">
      <!-- some content -->
    </TabItem>

    <TabItem Header="Second">
     <!-- some content -->
    </TabItem>

  </TabControl>

</Grid>

 

My sample contains two tabs which both display the same image. Accordingly, the code snippet above produces the following 3D effect when switching tabs:

transition

Author: Categories: WPF, WPF Controls Tags: ,

A base class for custom WPF binding markup extensions

April 16th, 2008

Already tried to extend the Binding or BindingBase classes in order to write your own custom bindings? And failed because BindingBase.ProvideValue is sealed? Me too…

The result is a MarkupExtension that works around the issue that you cannot properly extend the Binding class. Basically, it allows you to write binding expressions with the usual syntax without having to worry about the underlying plumbing. Here’s a sample binding that adds an additional LookupKey property:

<TextBox Name="txtZipCode"
         Text="{local:LookupExtension Path=ZipCode,
                                      Mode=TwoWay,
                                      UpdateSourceTrigger=PropertyChanged,
                                      LookupKey=F5}"
/>

Decorating the Binding class

As extending the Binding class did not work, I tried a different approach:

  • Create a class that extends MarkupExtension rather than BindingBase. This class provides all the properties that are needed for a binding expression (Source, Path, Converter, …).
  • Based on defined binding properties, the extension class internally creates a regular Binding and associates it with the targeted dependency object.

I wanted it to look somehow like this (dummy code!):

public class MyCustomExtension : MarkupExtension
{
  public override object ProvideValue(IServiceProvider provider)
  {
    //we only use this extension on textboxes
    TextBox tb = GetTextBoxFromProvider(provider);

    //create a binding and associate it with the text box
    Binding binding = CreateBinding(this.Source, this.Path);
    tb.SetBinding(TextBox.TextProperty, binding);

    //return a valid value
    return ...;
  }
}

And guess what – that worked 🙂

The result is an abstract base class that provides pretty much everything you need to create your custom binding classes. The BindingDecoratorBase provides properties for all kinds of binding expressions (Source, Path, Converter etc.) and handles binding creation and association with the targeted dependency object for you:

image

Basically, the class maintains its own binding class and just forwards the binding statements. For example, here’s the declaration of the Path property:

[DefaultValue(null)]
public PropertyPath Path
{
  get { return binding.Path; }
  set { binding.Path = value; }
}

Custom Binding Sample

Here’s a simple sample: Let’s say we have a TextBox that displays the ZipCode property of a bound item. The XAML for this bound control looks like this:

<TextBox Name="txtZipCode"
         Text="{Binding Path=ZipCode}"
/>

However, we want to interfere with the binding in order to add some additional value. For this example, we’d like to register the bound control with some kind of handler class. We could also do this with an attached property, but this is more fun 😉

First, I created a custom extension called LookupExtension that derives from BindingDecoratorBase. BindingDecoratorBase provides all binding properties out of the box, so the binding expression itself (Path=ZipCode) remains intact. The only thing I had to change in XAML was the extension name and add the custom property for my extension (LookupKey):

<TextBox Name="txtZipCode"
         Text="{local:LookupExtension Path=ZipCode,
                                      LookupKey=F5}"
/>

As LookupExtension derives from BindingDecoratorBase, it is ensured that in the end, the text box will be bound to the ZipCode property just like with the original regular binding expression.

Below is a first implementation which does not yet add any additional value. Therefore, this extension would behave exactly like the original binding – the ZipCode property of the bound data item is displayed, and updating the TextBox changes the bound property value:

public class LookupExtension : BindingDecoratorBase
{
  //A property that can be set in XAML
  public string LookupKey { get; set; }

  public override object ProvideValue(IServiceProvider provider)
  {
    //delegate binding creation etc. to the base class
    return base.ProvideValue(provider);
  }
}

So what’s left is adding some custom code to the extension. Below is the complete sample. Basically, the bound control (the text box of the sample) is determined by invoking TryGetTargetItems and then registered with an InputHandler. That’s it:

public class LookupExtension : BindingDecoratorBase
{
  //A property that can be set in XAML
  public string LookupKey { get; set; }

  public override object ProvideValue(IServiceProvider provider)
  {
    //delegate binding creation etc. to the base class
    object val = base.ProvideValue(provider);

    //try to get bound items for our custom work
    DependencyObject targetObject;
    DependencyProperty targetProperty;
    bool status = TryGetTargetItems(provider, out targetObject,
                                              out targetProperty);

    if (status)
    {
      //associate an input listener with the control
      InputHandler.RegisterHandler(targetObject, LookupKey);
    }

    return val;
  }
}

Note the status flag in the snippet above! ProvideValue is also invoked at design time (within Visual Studio). In this case, the provider parameter is null, so be careful to validate your parameters or you’ll end up with a broken designer.

 

Problem: Attribute syntax with resources

During the implementation of the sample, I came across an annoying issue: You cannot nest static or dynamic resources within a custom markup extension due to a framework bug. This means that if you wanted to set the Source property explicitly, you could not write it like this:

<TextBox Name="txtZipCode"
         Text="{local:LookupExtension Source={StaticResource MyAddress}
                                      Path=ZipCode,
                                      LookupKey=F5}"
/>

The above snippet does not compile due to a bug I described here. As a result, you have to fall back to property element syntax if you need to explicitly setting the Source property or other resources (e.g. Converter):

<TextBox Name="txtZipCode">
  <TextBox.Text>
    <local:LookupExtension Source="{StaticResource MyAddress}"
                           Path="ZipCode"
                           LookupKey="F5" />
  </TextBox.Text>
</TextBox>

 

Source Code / Sample

I’ve assembled a simple project that contains the BindingDecoratorBase class and the LookupExtension I used as a sample (VS 2008 project).

You can download it here: custom-bindings.zip

Markup Extension Sample

 

Author: Categories: WPF Tags: ,

Custom MarkupExtension && Nested Extensions == Bug

April 16th, 2008

I’m currently working on a custom markup extension and came over a pretty nasty issue. Here’s the working XAML of a dummy extension:

<TextBox Name="txtCity"
   Foreground="{local:ColorExtension Color=Red}"
/>

 

This works like a charm – the fore color is set to red as expected. However – as soon as I try to set the Color property through a resource, I’m getting a compiler error:

<TextBox Name="txtCity"
   Foreground="{local:ColorExtension Color={StaticResource ErrorBrush}}"
/>

Here’s the error message: Unknown property ‘Color’ for type ‘MS.Internal.Markup.MarkupExtensionParser+UnknownMarkupExtension’ encountered while parsing a Markup Extension.

 

Well, the property does exist. Fortunately, Beatriz Costa referred to this bug in her blog – in October 2006. I’m working here with VS2008, targeting .NET 3.5, so I can honestly say: I’m not amused. Fortunately, there’s a workaround: Skip attribute syntax and fall back to property element syntax:

<TextBox Name="txtCity">
  <TextBox.Foreground>
    <local:ColorExtension Color="{StaticResource ErrorBrush}" />
  </TextBox.Foreground>
</TextBox>

 

Another solution would be to assign a constructor to the ColorExtension markup extension that takes the Brush as a parameter. In that case, you could write XAML like this:

<TextBox Name="txtCity"
   Foreground="{local:ColorExtension {StaticResource ErrorBrush}}"
/>

The compiler accepts a StaticResource as a constructor parameter, but it appears it breaks the VS designer. So for now, it’s property element syntax.

 

Some other observations: Some extensions can be nested, others can’t. Using DynamicResource also fails to compile, while using a RelativeSource statement or something like {x:Null} works without complaints.

If somebody can shed some light on this, I’ll be happy to update this post accordingly 🙂

Author: Categories: WPF Tags: ,

WPF TreeView Update

April 7th, 2008

I’ve posted an update for my WPF TreeView which contains a bugfix and two new features:

  • The root item collection is now monitored for changes, and the tree updates itself automatically. This behaviour, however, can be controlled through the ObserveRootItems dependency property.
  • Built-in filtering support through a strongly typed predicate. I’m not completely happy with my implementation though – as a matter of fact, I’ve already started to rewrite it completely – you can expect the next version within the next 10 days. The filtering API however, will remain intact.

In case you did override some of the tree’s virtual methods, your project might not compile out of the box because some of these methods now receive additional parameters. However, as nothing has been removed, adjusting your code should be a matter of seconds.

I’ve added the download link to the original post:
http://www.hardcodet.net/2008/01/wpf-treeview

Happy coding 🙂

Author: Categories: Open Source, WPF TreeView Tags: , ,

Property declaration snippets for ReSharper

March 21st, 2008

Automatic properties in .NET 3.5 are a nice thing, but they are out of the equation if you want to take advantage of the almighty INotifyPropertyChanged interface which plays a crucial role in WPF. Here’s a set of ReSharper snippets that simplify interface implementation and property declaration.

Event Declaration

The first snippet just prints out an interface implementation and adds some additional value to it, including a runtime check of property names in Debug builds (credits go to Josh Smith for this one). Just type inpc to print out this statement:

#region INotifyPropertyChanged event

///<summary>
///Occurs when a property value changes.
///</summary>
public event PropertyChangedEventHandler PropertyChanged;


/// <summary>
/// Raises the <see cref="PropertyChanged"/> event for
/// a given property.
/// </summary>
/// <param name="propertyName">The name of the changed property.</param>
protected void OnPropertyChanged(string propertyName)
{
  //validate the property name in debug builds
  VerifyProperty(propertyName);

  if (PropertyChanged != null)
  {
    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  }
}


/// <summary>
/// Verifies whether the current class provides a property with a given
/// name. This method is only invoked in debug builds, and results in
/// a runtime exception if the <see cref="OnPropertyChanged"/> method
/// is being invoked with an invalid property name. This may happen if
/// a property's name was changed but not the parameter of the property's
/// invocation of <see cref="OnPropertyChanged"/>.
/// </summary>
/// <param name="propertyName">The name of the changed property.</param>
[Conditional("DEBUG")]
private void VerifyProperty(string propertyName)
{
  Type type = this.GetType();

  //look for a *public* property with the specified name
  PropertyInfo pi = type.GetProperty(propertyName);
  if (pi == null)
  {
    //there is no matching property - notify the developer
    string msg = "OnPropertyChanged was invoked with invalid property name {0}: ";
    msg += "{0} is not a public property of {1}.";
    msg = String.Format(msg, propertyName, type.FullName);
    Debug.Fail(msg);
  }
}

#endregion

 

…and don’t forget to declare the INotifyPropertyChanged implementation. The snippet won’t do that for you:

public class Class1 : INotifyPropertyChanged

 

Property Declaration

The second snippet (shortcut is pcp) simplifies the declaration of a given property for you. You can define property name, type, default value and a description summary. The generated code for a sample property looks like this:

#region UserId

/// <summary>
/// The numeric ID of the user. Defaults to null.
/// </summary>
private int? userId = null;


/// <summary>
/// The numeric ID of the user. Defaults to null.
/// </summary>
public int? UserId
{
  get { return userId; }
  set
  {
    //ignore if values are equal
    if (value == userId) return;

    userId = value;
    OnPropertyChanged("UserId");
  }
}

#endregion

 

Grab the snippet here: Download

Author: Categories: C#, ReSharper, WPF Tags: , ,

WPF is for LOB – and we can even do RAD (WTF?)

March 18th, 2008

Agreed – the WPF learning curve is steep, but once one figures out how the basics work, things tend to get amazingly easy. And of course, the emerging sets of toolkits dont’t hurt either.

Here’s another sample – a customer of mine needed a utility to maintain data in their web shop (MySql) and update the shop database based on external data. Here’s the result of about 1.5 days work, starting pretty much from scratch (click on thumbnail for the screenshot):

pw_shopadmin

And once more, I have to say: LLBLGen ist a wonderful tool – setting up database mappings is a breeze, and the generated entities play very nice with WPF. Kudos to Frans Bourma for this one!

Author: Categories: WPF Tags: ,