Colin Eberhardt's Adventures in WPF

Silverlight MultiBindings, How to attached multiple bindings to a single property.

June 25th, 2009

This blog posts describes a technique for associating multiple bindings with a single dependency property within Silverlight applications. WPF already has this functionality in the form of MultiBindings, the code in this post emulates this function.

UPDATE: Silverlight 4, attached properties and multiple property bindings are all supported in my latest update here.

The simple application below demonstrates this technique, where there are three data-entry text boxes bound to the individual properties of a simple Person object, with the title text block being bound to both the Forename and Surname properties. Try editing the surname or forename fields and watch as the title is updated.

The XAML for this application looks something like this (superfluous properties/ elements removed for clarity):

<TextBlock Foreground="White" FontSize="13">
    <local:BindingUtil.MultiBinding>
        <local:MultiBinding TargetProperty="Text" Converter="{StaticResource TitleConverter}">
            <Binding Path="Surname"/>                            
            <Binding Path="Forename"/>
        </local:MultiBinding>
    </local:BindingUtil.MultiBinding>
</TextBlock>
 
<TextBlock Text="Surname:"/>
<TextBox  Text="{Binding Path=Surname, Mode=TwoWay}"/>
 
<TextBlock Text="Forename:"/>
<TextBox Text="{Binding Path=Forename, Mode=TwoWay}"/>
 
<TextBlock Text="Age:"/>
<TextBox Text="{Binding Path=Age, Mode=TwoWay}"/>

The Solution

My solution to the problem of multi-binding was to introduce a class, MultiBinding which is associated with the element which has out multi-binding target property via the BindingUtil.MultiBinding attached property. The following diagram details my idea:

multibinding

The Forename and Surname bindings are bound to properties of the MultiBinding (Exactly which properties we will get onto in a minute). The MultiBinding has an associated Converter of type IMultiValueConverter, this client supplied class implements the conversion process, as shown below:

public class TitleConverter : IMultiValueConverter
{
 
  public object Convert(object[] values, Type targetType,
    object parameter, System.Globalization.CultureInfo culture)
  {
    string forename = values[0] as string;
    string surname = values[1] as string;
 
    return string.Format("{0}, {1}", surname, forename);
  }
}

The IMultiValueConverter interface is much the same as the IValueConverter, except in this case an array of objects are passed to the converter, with each object containing the current bound value for each of our bindings in order.

With this value converter, the MultiBinding class can detect changes in the two bindings, then, recompute the ConvertedValue which is bound to the target property of our TextBlock. This was my initial idea, and it certainly sound quite simple, however it was not quite as easy as it seams on first inspection!

Hijacking the DataContext

Typically when defining a binding we omit the Source property, e.g. {Binding Path=Forename}. When the Binding which this expression represents is associated with an element, the binding source will be the (possibly inherited) DataContext of the target element. Therefore, in order to allow binding on the MultiBinding class, it must be a FrameworkElement, this gives us the DataContext property and the SetBinding() method.

However, there is a problem; each element’s DataContext is inherited from its parent within the visual tree. Our MultiBinding is not within the visual tree and we do not want it to be, therefore it will not participate in DataContext inheritance. What we need to do is ensure that when DataContext changes on the element which the MultiBinding is associated with it, that we ‘push’ this DataContext onto the MultiBinding. With WPF this is easy, FrameWorkElement exposes a DataContextChanged event, (for DPs that do not expose events there’s always the DependencyPropertyDescriptor). However, with Silverlight, neither of these options are available.

My solution here is to create a new attached property and attach it to the target element (our TextBlock in this case), which piggy-backs the DataContext. The code below is from the BindingUtil class, when the MultiBinding class is associated with the target element as an attached property, we also bind its attached DataContextPiggyBack property. We define a static method which is invoked whenever the DatatContext of the target element changes, and here we ‘push’ this new DataContext to the MultiBinding class.

/// <summary>
/// Invoked when the MultiBinding property is set on a framework element
/// </summary>
private static void OnMultiBindingChanged(DependencyObject depObj,
  DependencyPropertyChangedEventArgs e)
{
  FrameworkElement targetElement = depObj as FrameworkElement;
 
  // bind the target elements DataContext, to our DataContextPiggyBack property
  // this allows us to get property changed events when the targetElement
  // DataContext changes
  targetElement.SetBinding(BindingUtil.DataContextPiggyBackProperty, new Binding());
}
 
 
public static readonly DependencyProperty DataContextPiggyBackProperty =
    DependencyProperty.RegisterAttached("DataContextPiggyBack",
        typeof(object), typeof(BindingUtil), new PropertyMetadata(null,
              new PropertyChangedCallback(OnDataContextPiggyBackChanged)));
 
public static object GetDataContextPiggyBack(DependencyObject d)
{
  return (object)d.GetValue(DataContextPiggyBackProperty);
}
 
public static void SetDataContextPiggyBack(DependencyObject d, object value)
{
  d.SetValue(DataContextPiggyBackProperty, value);
}
 
/// <summary>
/// Handles changes to the DataContextPiggyBack property.
/// </summary>
private static void OnDataContextPiggyBackChanged(DependencyObject d,
                                                              DependencyPropertyChangedEventArgs e)
{
  FrameworkElement targetElement = d as FrameworkElement;
 
  // whenever the targeElement DataContext is changed, copy the updated property
  // value to our MultiBinding.
  MultiBinding relay = GetMultiBinding(targetElement);
  relay.DataContext = targetElement.DataContext;
}

Creating targets for the bindings

The MultiBinding class needs to have a property which is a collection of type Binding:

[ContentProperty("Bindings")]
public class MultiBinding : Panel, INotifyPropertyChanged
{
 
  ...
 
  /// <summary>
  /// The bindings, the result of which are supplied to the converter.
  /// </summary>
  public ObservableCollection<Binding> Bindings { get; set; }
 
  ...
}

(Note the use of the ContentProperty attribute, which means that we do not have to explicitly detail Binding collection in XAML using the property element syntax). The problem is, in order for these bindings to be evaluated, they need to be bound to a target property. We could add a number of ‘dummy’ properties to MultiBinding, PropertyOne, PropertyTwo, etc … and bind to these, however this approach is cumbersome and limited.

The solution here is to make MultiBinding a Panel, this allows it to have child elements, each of which will inherit its DataContext. When the MultiBinding class is initialised at the point it is attached, the Initialise method is invoked. This method creates an instance of BindingSlave, a simple FrameworkElement subclass with a single Value property which raises PropertyChanged events when this property changes, for each binding:

/// <summary>
/// Creates a BindingSlave for each Binding and binds the Value
/// accordingly.
/// </summary>
internal void Initialise()
{
  foreach (Binding binding in Bindings)
  {
    BindingSlave slave = new BindingSlave();
    slave.SetBinding(BindingSlave.ValueProperty, binding);
    slave.PropertyChanged += new PropertyChangedEventHandler(Slave_PropertyChanged);
    Children.Add(slave);
  }            
}

Whenever a slave property changes, the MultiBinding event handler obtains the current bound values and uses them to re-evaluate the converter:

/// <summary>
/// Invoked when any of the BindingSlave's Value property changes.
/// </summary>
private void Slave_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
  List<object> values = new List<object>();
  foreach (BindingSlave slave in Children)
  {
    values.Add(slave.Value);
  }
  ConvertedValue = Converter.Convert(values.ToArray(), typeof(object), ConverterParameter,
    CultureInfo.CurrentCulture);
}

The ConvertedValue property is bound to the target property of the target element, and will be updated to reflect this change.

This method is very similar to one which Josh Smith described in his codeproject article on the concept of Virtual Branches. The MultiBinding and BindingSlave instances can be thought of as a virtual branch to our visual tree:

virtualbranch

Download Sources

You can download the full sourcecode for this project here: slmultibinding.zip

A final word on MVVM

The MVVM pattern is very popular in Silverlight and WPF application development. With this pattern, your view’s DataContext is bound to your view-model. With this pattern in place, the need for multi-bindings can be removed (Josh Smith goes further to moot the concept of removing value converters altogether). In our example the PersonViewModel class would simply expose a Title property which performs the same function as the TitleConverter. So does this render my technique completely redundant?

I don’t think so. Whilst MVVM is a great pattern, there are times where adding another layer to your application may be undesirable, especially if your primary aim is simplicity. Furthermore, I do not like being forced into using a specific pattern simply because the framework itself is lacking in functionality. The MVVM pattern is great for building skinnable applications, and allowing UI unit testing, however, if I do not need either of these features, I would prefer not to MVVM.

Regards, Colin E.

Exposing Bindings as Properties of a Control

June 19th, 2009

card

I must admit that the title of this post is not entirely clear, however I couldn’t find a way to sum up the content in one short sentence, so we’ll dive straight into an example. Let’s say for example you have developed a funky little business-card as illustrated above, using the simple XAML below:

<Border BorderBrush="LightGray" Background="White"  BorderThickness="1.5" CornerRadius="20"
        Width="220" Height="120">
    <Border Margin="5" BorderBrush="LightGray" BorderThickness="1.5" CornerRadius="15">
        <Border.Background>
            <ImageBrush>
                <ImageBrush.ImageSource>
                    <BitmapImage UriSource="back.jpg" />
                </ImageBrush.ImageSource>
            </ImageBrush>
        </Border.Background>
 
        <StackPanel Orientation="Vertical" Margin="10">
            <TextBlock Text="{Binding Name}"
                       FontSize="15" FontWeight="Bold" />
            <Rectangle Stroke="DarkGray" HorizontalAlignment="Stretch"
                       StrokeThickness="0.5" Fill="Black" Height="1"/>
            <TextBlock Margin="0,10,0,0"  Text="{Binding Company}"/>
            <StackPanel Orientation="Horizontal" >
                <TextBlock Text="e: " FontSize="10"/>
                <TextBlock Text="{Binding Email}" FontSize="10"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="w: " FontSize="10"/>
                <HyperlinkButton Content="{Binding Web}" FontSize="10"
                             NavigateUri="{Binding Web}"/>
            </StackPanel>
        </StackPanel>
    </Border>
</Border>

The above XAML creates a simple visual layout that binds to the Name, Email, Web and Company properties of the data object which is presented to the inherited DataContext. Nice and simple.

Now, let’s say you want to re-use this XAML markup in a number of places across your application. The obvious solution is to package it within a UserControl. However, elsewhere within the application contact details are stored in different types, with different properties, perhaps the property Web is used in some places, whereas the property URL is used elsewhere. If our UserControl simply contains the XAML markup given above, the binding paths are hard-coded and inflexible. So, how do we package the above markup for re-use whilst maintaining flexibility?

In UI frameworks which do not support databinding the obvious choice would be to define an interface IContactDetails, which defines a compile-time contract that clients of the control must implement on their business objects. This would allow us to enforce the presence of properties with specific names. However, with WPF / Silverlight the binding framework removes the need for controls to demand the presence of a certain interface and life is now much better as a result!

So … what we really want here is to allow the clients of our ContactDetails user control to provide bindings for the various framework elements within the user control itself.

Bindings can be constructed in code-behind by invoking the SetBinding method defined on DependencyObject as show in the example below:

// create a binding with a given source and property-path
Binding binding = new Binding();
binding.Source = myClass;
binding.Path = new PropertyPath("WindowTitle");
// bind the button's Content property
button.SetBinding(Button.ContentProperty, binding);

Therefore, if we were to expose the various Bindings as properties of the control (hence this blog post’s title), we could set the name, email, web elements binding accordingly using the Setbinding method.

The first time I tried this I added a NameBinding dependency property of type Binding to my UserControl, so that the client XAML looked as follows:

<local:ContactDetailsControl
    NameBinding="{Binding Name}"/>

However, this didn’t quite have the desired effect. When the XAML reader processes the above markup it creates the Binding object that we are after, however it does not set the NameBinding property value to this binding. Instead, it uses it to bind the NameBinding property.

The solution to the problem is to make NameBinding a standard CLR property. This time when the XAML reader encounters the above markup it once again creates the Binding object, but since NameBinding is not a dependency property it does not use it to bind the property, it simply sets the property value.

The code-behind of our ContactDetails user control looks like this:

public partial class ContactDetailsControl : UserControl
{
    public Binding NameBinding { get; set; }
    public Binding CompanyBinding { get; set; }
    public Binding WebBinding { get; set; }
    public Binding EmailBinding { get; set; }
 
    public ContactDetailsControl()
    {
        InitializeComponent();
    }
 
    private void Border_Loaded(object sender, RoutedEventArgs e)
    {
        nameText.SetBinding(TextBlock.TextProperty, NameBinding);
        webText.SetBinding(HyperlinkButton.ContentProperty, WebBinding);
        webText.SetBinding(HyperlinkButton.NavigateUriProperty, WebBinding);
        companyText.SetBinding(TextBlock.TextProperty, CompanyBinding);
        emailText.SetBinding(TextBlock.TextProperty, EmailBinding);
    }
}

The four bindings are exposed as CLR properties. When the UI is Loaded, we use them to bind the various elements within the control. The net result is that we now have a re-useable control whilst maintaining the flexibility provided by the binding framework, as illustrated by its usage below:

<local:ContactDetailsControl
    NameBinding="{Binding FullName}"
    WebBinding="{Binding Website}"
    CompanyBinding="{Binding Company}"
    EmailBinding="{Binding Email}"/>

Now for another example and a bit more fun …

The above Silverlight application shows a number of particles exhibiting Brownian motion.

This application creates 50 instances of a Particle object within an ObservableCollection:

class Particle : INotifyPropertyChanged
{
    public double XLocation { ... }
    public double YLocation { ... }
    public double Excitement { ... }
}

The particles are rendered by a ScatterControl, which is a UserControl:

<Border BorderBrush="LightGray" BorderThickness="1">
    <!-- ItemsSource property set in code-behind -->
    <local:ScatterControl x:Name="scatterControl"
                      XValueBinding="{Binding Path=XLocation}"
                      YValueBinding="{Binding Path=YLocation}"
                      FillBinding="{Binding Path=Excitement,
                            Converter={StaticResource FillConverter}}"/>
</Border>

This control has an ItemsSource property of type IEnumerable, and exposes three other properties of type Binding.

The markup for this control is given below:

<UserControl ... >
 
    <ItemsControl x:Name="itemsControl">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Canvas>
                    <Ellipse Width="10" Height="10" Fill="Red"
                             Loaded="Ellipse_Loaded"/>
                </Canvas>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>    
</UserControl>

The particles are rendered using an ItemsControl, which creates an instance of an Ellipse for each bound particle and places it within a Canvas (As defined by the ItemsControl.ItemsPanel property). As each ellipse is loaded, we set the bindings in code-behind:

private void Ellipse_Loaded(object sender, RoutedEventArgs e)
{
    Ellipse ellipse = sender as Ellipse;
    ellipse.SetBinding(Canvas.LeftProperty, XValueBinding);
    ellipse.SetBinding(Canvas.TopProperty, YValueBinding);
    ellipse.SetBinding(Ellipse.FillProperty, FillBinding);
}

Again, by exposing Bindings as properties this user control is just as flexible as if its markup was included in the page directly. This example also illustrates another interesting point, the Bindings that the client provided have been re-used for each Ellipse that was created by the ItemsControl. This is made possible because when SetBinding is invoked on our Ellipse, the Binding is not associated with the Ellipse, rather, it is used to create an instance of a BindingExpression. Binding is used to declare a binding, whereas BindingExpression is the implementation, i.e. it does the heavy-lifting of copying data to-and-from from source to target (and vice-versa).

You can download the full source for both examples: bindingproperties.zip

Regards, Colin E.

Dependency Property Performance and Lissajous Figures

June 2nd, 2009

A few night ago I was working on a Siverlight control which renders some quite complex Paths, the geometry of which is determined from a number of dependency properties. In order to gain UI coolness points I wanted to animate the dependency properties in order to see a smooth transition of the Path geometry between the old and new values. The animation itself was easy to implement, but the resultant animation was distinctly choppy.

Now, I cannot share the code of the Silverlight control I was working on, so I have decided to illustrate the point via a Lissajous Figure. These curves are plotted using the following simple formula:

A simple Lissajous Figure can be constructed by creating a UserControl which dependency properties for the various parameters in the above equations. The control contains a single path whose Data property will be set to a suitable geometry in code behind, and a ‘container’ element for our path which we use to determine the width / height of our curve.

<UserControl ...>
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid x:Name="PathContainer" Margin="5">            
            <Path x:Name="lissajousFigure" Stroke="#9EFFFF" StrokeThickness="1"/>
        </Grid>
    </Grid>
</UserControl>

The points that are used to construct the geometry are calculated from the ActualXFrequency, ActualYFrequency, ActualPhase properties of our user control, together with the ActualWidth and ActualHeight of the container in order to scale the curve appropriately.

for(double t = 0; t < Math.PI * 10; t += Math.PI / 36)
{
    points.Add(new Point()
    {
        X = PathContainer.ActualWidth * Math.Sin(t * ActualXFrequency) / 2
            + ActualWidth / 2,
        Y = PathContainer.ActualHeight * Math.Cos(t * ActualYFrequency + ActualPhase) / 2
            + PathContainer.ActualHeight / 2
    });
}

When I investigating the choppy animation performance in my Silverlight control I concentrated initially on other parts of the application; the construction of the paths, the property changed events and the resultant chain reaction of event which can result in a spiders-web of method invocations. It was not until a little later that I focussed on the code that constructed the geometry, which looks not too dissimilar to the above.

At first sight, the code looks just fine, we are performing a number of simple operations on a few simple properties. However, this is not the case, these properties are not simple CLR properties backed by value or reference types. These are Dependency Properties, which are much more complex beasts!

A quick change to the above code to ensure that the DP accessors are called only once, rather than 360 times, resulted in code which ran ~400 times faster!

double actualWidth = PathContainer.ActualWidth;
double actualHeight = PathContainer.ActualHeight;
double actualXFrequency = ActualXFrequency;
double actualPhase = ActualPhase;
double actualYFrequency = ActualYFrequency;
 
for(double t = 0; t < Math.PI * 10; t += Math.PI / 36)
{
    points.Add(new Point()
    {
        X = actualWidth * Math.Sin(t * actualXFrequency) / 2
            + actualWidth / 2,
        Y = actualHeight * Math.Cos(t * actualYFrequency + actualPhase) / 2
            + actualHeight / 2
    });
}

When you think about the features that the DP framework provides (databinding, animation, inheritance etc …), it is not at all surprising that this is at some performance cost. And I will forgive the reader if they tell me that I am stating the obvious! However, in code behind, where DPs are accessed via their CLR wrappers it is easy to forget this. It should also be noted that DPs are far from slow. It is only when they are used as part of a complex iterative calculations that the performance-hit will be felt.

Anyhow, this is a small lesson in what is possibly obvious! However, I must admit, I had far too much fun creating the Lissajous Figure example application as you can see from the app. at the start of this article … it takes me back to Physics lab at University!

A few other points of interest:

  • The code uses ElementName binding attached behaviour I created in an earlier blog post. As a result, there is no code-behind in the main page (I may be flirting with Silverlight but my WPF credibility remains intact!)
  • The various dependency properties for the Lissajous Figure user control are defined using T4 templates as described in this codeproject article.

I also really like the way that when one of the DPs such as Phase is updated, a storyboard is used to animate the accompanying ActualPhase DP to the updated value.

partial void OnPhasePropertyChanged(DependencyPropertyChangedEventArgs e)
{
    AnimateProperty("ActualPhase", Phase, 100);
}
 
private void AnimateProperty(string propertyName, double targetValue, int milliseconds)
{
    Storyboard sb = new Storyboard();
 
    DoubleAnimation b = new DoubleAnimation() { To = targetValue };
    b.Duration = new Duration(new TimeSpan(0, 0, 0, 0, milliseconds));
    sb.Children.Add(b);
    Storyboard.SetTarget(b, this);
    Storyboard.SetTargetProperty(b, new PropertyPath("(" + propertyName + ")"));
 
    sb.Begin();
}

This means that even though the slider controls bound to the DPs move in discrete steps, the above animation gives the illusion of the steps being continuous.

You can download the full project source here: silverlightdpperformance.zip.

[Oscilloscope image reproduced from Wikipedia under Creative Commons Licence]

Regards, Colin E.