Colin Eberhardt's Adventures in .NET

Silverlight MultiBinding solution for Silverlight 4

May 10th, 2010

In this post I describe an update to the Silverlight MultiBinding solution I presented last year. This update includes support for Silverlight 4, attached properties and multiple bindings on a single object.

UPDATE: I have updated this code to include ElementName and TwoWay binding. Grab the latest copy here.

MultiBinding is a WPF feature that allows you to bind a single property to a number of sources, with the source values being combined by a value converter. This is a feature that is missing from Silverlight. About a year ago I developed a MultiBinding solution for Silverlight, which has proven very popular! I even had an email from an Microsoft Attorney asking if they could use it in the Silverlight Facebook client (How cool is that :-) ). I was also very happy when Stefan Olson made a few updates to this code to allow multiple MultiBindings on a single object and spotted the SL4 issue. This blog post is a quick demonstration of these new features …

The following application is an example of MultiBindings in action:

In the above application, the TextBox at the top of the page is bound to both the surname and forename properties of our data-object via converter that takes the first letter of the forename and the surname. If you edit the surname or forename (hitting enter or changing focus to commit), the title is updated automatically. The title tooltip is bound to the all three object properties via a different value converter that concatenates all three.

The XAML for this binding is show below:

<TextBlock x:Name="Block" Foreground="White" FontSize="13" Margin="5,0,0,0">
    <local:BindingUtil.MultiBindings>
        <local:MultiBindings>
            <local:MultiBinding TargetProperty="Text"
                                Converter="{StaticResource TitleSummaryConverter}">
                <local:MultiBinding.Bindings>
                    <local:BindingCollection>
                        <Binding Path="Surname"/>                            
                        <Binding Path="Forename"/>
                        </local:BindingCollection>
                </local:MultiBinding.Bindings>
            </local:MultiBinding>
            <local:MultiBinding TargetProperty="ToolTipService.ToolTip"
                                Converter="{StaticResource TitleConverter}">
                <local:MultiBinding.Bindings>
                    <local:BindingCollection>
                        <Binding Path="Surname"/>                            
                        <Binding Path="Forename"/>
                        <Binding Path="Age"/>
                    </local:BindingCollection>
                </local:MultiBinding.Bindings>
            </local:MultiBinding>
        </local:MultiBindings>
    </local:BindingUtil.MultiBindings>
</TextBlock>

In the above you can see that our TextBlock has two multibindings, one on Forename and Surname, and the other which includes all three properties. Note, the second multibinding is on the ToolTipService.ToolTip attached property.

You can download the source for Silverlight MultiBinding here: SLMultiBindingUpdate.zip – thanks again to Stefan Olson who added WPF support to this technique.

If you are interested in the technical details of how this works, I refer you to the original article which describes how the code builds a ‘virtual’ branch on the visual tree in order to evaluate your bindings:

I hope this update is of use to SL4 developers. If you have any feedback, please leave a comment below.

You can download the source for Silverlight MultiBinding here: SLMultiBindingUpdate.zip

Regards, Colin E.

Binding a Silverlight 3 DataGrid to dynamic data via IDictionary (Updated)

March 26th, 2010

In this post I demonstrate a method for binding a Silverlight 3 DataGrid to dynamic data, i.e. data which does not have properties that are known at design time. This technique results in a bound grid which is sortable and editable. This blog post is a bug fix (due to differences between SL2 and SL3) and expansion on my previous posts on this subject.

WinForms, WPF and ASP.NET are all perfectly capable of binding to dynamic data via a DataGrid, or custom TypeDescriptors. However Silverlight has neither of these features. Around one year ago I published a pair of articles that demonstrated a technique that could be used to bind a DataGrid to dynamic data presented as a list of dictionaries. The first article detailed how to use a ValueConverter to access the cell values within a dictionary and how a custom CollectionView could be created to permit sorting. The second article showed how to extend this solution to enable editing within the grid.

These two blog posts have proven very popular, with 84 comments between them :-) . However I have seen a recurring theme in the comments to these posts which I will now address:

  1. SL3 Sorting – I have had a number of reports that indicate sorting is broken in Silverlight 3
  2. SL3 Editing – It looks like editing is also broken in SL3 :-(
  3. Adding columns in code behind – My examples configured columns in XAML, but for truly dynamic data this would have to be done in code-behind. A number of readers have had difficulty with converting the XAML into the required C# code.

This blog post will address these specific issues, providing a solution that works for SL3. If you are interested in the technical solution you might want to read the first and second blog posts before you read this one. The solution for SL3 is essentially the same, it is just a few subtle differences in the DataGrid that cause these issues.

Starting with the first of the SL3 problems, sorting. The DataGrid uses the SortDescriptions property of our collection which implements ICollectionView in order to sort the data. This remains unchanged in SL3. However, the ICollectionView implementation that I presented in the previous blog post did not implement all the methods on this interface, leaving out the ones that the SL2 DataGrid does not use.

When the SL3 DataGrid performs a sort or group operation, it first calls the DeferRefresh method on ICollectionView. This is quite a neat little method; what it does is allow you to suppress the events that the collection would typically raise whilst you make a number of changes, for example, applying a sort then a grouping, then raises a single collection changed event. This results in much less work being performed by the UI as it now handles a single event rather than multiple events. You can find a good example of how this works on Matt Manela’s blog. DeferRefresh is implemented by returning in IDisposable object, the implementation is quite trivial:

public class SortableCollectionDeferRefresh : IDisposable
{
    private readonly SortableCollectionView _collectionView;
 
    internal SortableCollectionDeferRefresh(SortableCollectionView collectionView)
    {
        _collectionView = collectionView;
    }
 
    public void Dispose()
    {
        // refresh the collection when disposed.
        _collectionView.Refresh();
    }
}

It is used by our collection as follows:

public class SortableCollectionView : ObservableCollection<Row>, ICollectionView
{
  ...
  public IDisposable DeferRefresh()
  {
      return new SortableCollectionDeferRefresh(this);
  }
  ...
}

That solves the sorting issue :-)

The lack of editing issue was a but odd, someone on the Silverlight forums indicated that they think this is an undocumented breaking change. With a SL3 DataGrid if you bind to a property of type object, the column becomes read-only, even if the DataGrid itself is not read-only. The solution is simply to set the IsReadOnly of each column to false.

With these few changes we now how a fully functioning DataGrid bound to our dynamic data:

The final recurring question to my previous blog posts is how to create the bound DataGrid columns in code-behind. To illustrate how this is done I will create an example where the DataGrid is bound to some XML that sits in a TextBox underneath the grid.

The example looks like this:

The two buttons in the centre allow you to synchronise the DataGrid and the XML, one formats the current grid contents in XML, the other takes the XML and dynamically binds the contents to the grid. You can try editing the data, then updating the XML and vice-versa. You can even add new columns to the XML data (hopefully the XML structure is pretty self explanatory – there is no error checking so take care ;-) ). The DataGrid is of course editable and sortable.

The interesting part of the code is the method that takes the XML contents and binds it to the grid. It is as follows:

/// <summary>
/// Copies the XML contents of the textbox into the DataGrid
/// </summary>
private void XmlToGrid()
{
  // clear the grid
  _dataGrid.ItemsSource = null;
  _dataGrid.Columns.Clear();
 
  // grab the xml into a XDocument
  XDocument xmlDoc = XDocument.Parse(_xmlInput.Text);
 
  // find the columns
  List<string> columnNames = xmlDoc.Descendants("column")
                                   .Attributes("name")
                                   .Select(a => a.Value)
                                   .ToList();
 
  // add them to the grid
  foreach (string columnName in columnNames)
  {
    _dataGrid.Columns.Add(CreateColumn(columnName));
  }
 
  SortableCollectionView data = new SortableCollectionView();
 
  // add the rows
  var rows = xmlDoc.Descendants("row");
  foreach (var row in rows)
  {
    Row rowData = new Row();
    int index = 0;
    var cells = row.Descendants("cell");
    foreach(var cell in cells)
    {
      rowData[columnNames[index]] = cell.Value;
      index++;
    }
    data.Add(rowData);
  }
 
  _dataGrid.ItemsSource = data;
}

The above code clears the grid, then uses a bit of Linq to XML to query the XML within the TextBox, creating the SortableCollectionView and Row instances which are the data objects for our dynamic data as described in the previous blog posts. The columns are created in code behind as follows:

private RowIndexConverter _rowIndexConverter = new RowIndexConverter();
 
private DataGridColumn CreateColumn(string property)
{
  return new DataGridTextColumn()
  {
    CanUserSort = true,
    Header = property,
    SortMemberPath = property,
    IsReadOnly = false,
    Binding = new Binding("Data")
    {
      Converter = _rowIndexConverter,
      ConverterParameter = property
    }
  };
}

This is really no different to the technique that you use when creating the column definitions in XAML. There is nothing special about XAML, it is essentially just an XML markup for creating objects.

Hopefully this blog post will help answer the recurring questions, and reduce the number of “it doesn’t work in SL3″ mails I get. Perhaps I will just get 84 “Thank you” comments instead :-)

You can download the full sourcecode for this blog post: SilverlightTable.zip

Regards, Colin E.

The mini-ViewModel pattern

August 7th, 2009

The construction of a ViewModel is often seen as the standard technique for solving binding problems within WPF and Silverlight. However, the addition of a ViewModel adds complexity to your code. This post describes an alternative method where a mini-ViewModel is applied directly to the problem areas in the view, leaving the rest to use simpler, straightforward binding to business objects.

One of the features of WPF / Silverlight that appealed to me immediately when I started to learn it was the flexibility of the binding framework. The concepts of DataContext inheritence and flexibility of the value converters results in a lot less glue-code, which makes me a happy developer! However, it does not take long before you start finding examples that just dont fit with the framework and things start to get just little more complex. This blog post describes one such example.

The example used in this blog post is of a very simple application which displays a business card. The business object rendered by the application, ContactDetails, has a number of simple CLR properties. Constructing a UI for viewing this business object is very easy, simply create an instance of this object (in a real application this object might come from a database or web service) and set it as the DataContext of the view:

public Page()
{
    InitializeComponent();
 
    ContactDetails details = new ContactDetails()
    {
        Company = "Scott Logic Ltd.",
        Email = "ceberhardt@scottlogic.co.uk",
        URL = "http://www.scottlogic.co.uk",
        Country = "UK",
        FullName = "Colin Eberhardt",
        PhoneNumber = 4408452241930
    };
 
    this.DataContext = details;
}

We then create some simple XAML with UI elements that bind to the various propeties of our object …

<Grid x:Name="LayoutRoot" Background="White">
    <Border BorderBrush="LightGray" Background="White"  BorderThickness="1.5" CornerRadius="20"
        VerticalAlignment="Center" HorizontalAlignment="Center">
        <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 FullName}"
                           FontSize="15"
                           FontWeight="Bold" />
                <Rectangle Stroke="DarkGray" HorizontalAlignment="Stretch"
                           StrokeThickness="0.5" Height="1"/>
                <TextBlock Text="{Binding Company}" Margin="0,10,0,0"/>
                <StackPanel Orientation="Horizontal" >
                    <TextBlock Text="e: "/>
                    <TextBlock Text="{Binding Email}" />
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="w: "/>
                    <HyperlinkButton Content="{Binding URL}"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="p: "/>
                    <TextBlock Text="{Binding PhoneNumber}"/>
                </StackPanel>
            </StackPanel>
        </Border>
    </Border>
</Grid>

And we get a lovely looking business card:

card

One problem with the above example is the phone number, outputting the raw number ’4408452241930′ is not terribly readable, besides phone numbers have a standard format, in this case, the phone number would be represented as ‘+44 (0)845 2241930′. Also, let’s make the problem more interesting; you might want to highlight the international dialing code in a different colour, or, if the application is being used by a UK client, display the number in a local format without the international code ’0845 2241930′. So just how do we achieve this?

In order to break the number up into different blocks of text, with different colours (i.e. styles), we need to modify our view to have multiple TextBlocks mapped to the PhoneNumber property of our business object. The part of our view which renders the phone number is modified as follows:

<StackPanel Orientation="Horizontal">
    <TextBlock Text="p: "/>
    <TextBlock Text="... country code ..." Foreground="LightGray"/>
    <TextBlock Text="... area code ..."/>
    <TextBlock Text="... local number ..."/>
</StackPanel>

But just how exactly do we bind the properties of these business objects?

One approach would be to use a value converter for each binding in order to extract the required part of the number, for example a CountryCodeValueConverter could be implemented which grabs the first 2 digits of the number. However, this approach is a little inelligent in that it fragments our logic into a number of separate classes, furthermore, if we want country specific formatting this requires the use of multibindings, which can be rather cumbersome if over-used (for a Silverlight implementation of multi bindings see my blog post from earlier this year).

Another approach which is often used to tackle tricky binding problems is the use of the Model-View-ViewModel (MVVM) pattern. With this pattern, our ContactDetails object is the Model, we construct a ViewModel which is a UI-oriented abstraction of the Model and it is this which we bind to the View. WPF guru Josh Smith describes MVVM as “a value converter on steroids” in order to highlight the usefulness of the pattern in this context.

The basic approach used here is to bind your View to a ViewModel rather than binding it to the business object directly. The ViewModel is specific to the view and wraps the business object (i.e. Model), forwarding the property values and change notification to the View. This extra layer allows us to supplement the properties of the Model object, adding new computed properties which are specific to the View. In this case, these computed properties can be used to expose ‘country code’, ‘area code’, etc… to our View.

(This is a common pattern so I am not going to reproduce the code required here, however, if you are interested, the attached sourcecode accompanying this article contains a regular ViewModel version as well as a mini-ViewModel implementation)

Whilst this approach works, my issue with it is that it adds quite a bit of boiler-plate code for wrapping properties, forwarding events etc … The removal of this glue-code is the exact reason that I like WPF/Silverlight so much! The MVVM pattern is primarily for supporting the designer-developer paradigm and enabling unit testing of UI applications, in my opinion the use of MVVM for anything else is just plain wrong!

So, how can we solve the problem of providing a nicely formatted phone number without the pain of bashing out line-after-line line of boiler-plate MVVM code? My solution to the problem isn’t to dispose of the MVVM pattern altogether, rather, it is to localise its usage to just the problem area. The first step is to encapsulate the rendering of the phone number as a user control:

...
<StackPanel Orientation="Horizontal">
    <TextBlock Text="p: "/>
    <local:PhoneNumberControl Number="{Binding PhoneNumber}" />
</StackPanel>
...

… which probably makes sense anyway from a perspective of good design and code re-use!

Now that we have moved the phone number property within the PhoneNumberControl we have isolated the problem and can deal with it locally. We can create a PhoneNumberControlViewModel which splits the phone number up into its various components and bind this to the PhoneNumberControl.

The control’s ViewModel looks something like this:

public class PhoneNumberControlViewModel : INotifyPropertyChanged
{
    public PhoneNumberControlViewModel(PhoneNumberControl ctrl)
    {
        _ctrl = ctrl;
        ComputeProperties();
 
        // listen to property changes in the control (we are interested
        // in just the Number property)
        _ctrl.PropertyChanged += Control_PropertyChanged;
    }
 
    private PhoneNumberControl _ctrl;
 
    private string _countryCodeText;
 
    private string _areaCodeText;
 
    private string _localNumberText;
 
    public string CountryCodeText
    {
        get { return _countryCodeText; }
        set { _countryCodeText = value; OnPropertyChanged("CountryCodeText");  }
    }
 
    public string AreaCodeText
    {
        get { return _areaCodeText; }
        set { _areaCodeText = value; OnPropertyChanged("AreaCodeText"); }
    }
 
    public string LocalNumberText
    {
        get { return _localNumberText; }
        set { _localNumberText = value; OnPropertyChanged("LocalNumberText"); }
    }
 
    private void Control_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "Number" || e.PropertyName == "Country")
        {
            ComputeProperties();
        }
    }
 
    private void ComputeProperties()
    {
        string formattedNumber = _ctrl.Number.ToString();           
        CountryCodeText = "+" + formattedNumber.Substring(0, 2);
        AreaCodeText = " (" + formattedNumber.Substring(2, 1) + ")" + formattedNumber.Substring(3, 3);
        LocalNumberText = " " + formattedNumber.Substring(6);
    }
}

Note that here the ViewModel is ‘wrapping’ the PhoneNumberControl rather than an instance of some Business / Model object.

Now we just set our ViewModel as the DataContext for the View, as per the typical usage of this pattern:

public PhoneNumberControl()
{
    InitializeComponent();
 
    this.DataContext = new PhoneNumberControlViewModel(this);
}

… and it doesn’t work. If you try the above, you will find that the binding on the PhoneNumberControls Number property no longer works. So why is this? if you look back at where the PhoneNumberControl instance is defined in our business card’s XAML markup you see that its Number property is bound as follows:

<local:PhoneNumberControl Number="{Binding PhoneNumber}" />

The source of this binding is not explicitly set, so will default to using the DataContext of the PhoneNumberControl instance. However, we have just changed this DataContext in our constructor to something else … oops!

Solving this problem is actually quite simple, the PhoneNumberControl markup is as follows:

<UserControl x:Class="SLMiniViewModel.PhoneNumberControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel x:Name="LayoutRoot" Orientation="Horizontal">
        <TextBlock Text="{Binding CountryCodeText}" Foreground="DarkGray"/>
        <TextBlock Text="{Binding AreaCodeText}"/>
        <TextBlock Text="{Binding LocalNumberText}"/>
    </StackPanel>
</UserControl>

If we modify our binding to the ViewModel as follows:

public PhoneNumberControl()
{
    InitializeComponent();
 
    LayoutRoot.DataContext = new PhoneNumberControlViewModel(this);
}

The subtle difference being that the ViewModel is now bound to the StackPanel which is the root of our visual tree within the control. This means that the PhoneNumberControl DataContext is still inherited from the business card and is our business object instance, the DataContext switch to the ViewModel is now neatly tucked just within the PhoneNumberControls visual tree, and it is this DataContext which our TextBlocks will inherit and bind to.

The result is that we can now use our mini-ViewModel embedded within the PhoneNumberControl to expose properties which are more amenable to binding to our View:

card2

Whilst this is a quite trivial example, in real-world applications, more complex examples where the data representation within the View is dependant on a number of properties are quite common. The source code accompanying this article extends the example a little further by making the formatting dependant on a second property of the business object. This is the sort of problem that would either push you towards multi-binding and numerous fragmented value converters, or a ViewModel.

In conclusion, the use of a mini-ViewModel which is embedded within a UserControl allows you to solve tricky binding problems without being weighed down by rolling out the MVVM pattern across your entire View. I am not against the MVVM pattern in itself, however I do firmly believe that it should only be used to solve the problems which it is was specifically designed for, i.e. supporting the designer-developer workflow and unit testing.

You can download the source-code for this article: SLMiniViewModel.zip – this project contains both MVVM and mini-MVVM implementations (count the number of lines in the ViewModel and contrast it with the mini-ViewModel).

Regards, Colin E.

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.