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:
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:
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.
Tags: binding, multibinding, silverlight


email: ceberhardt@scottlogic.co.uk
on Google+





Very Nice article and well explained.
I have a doubt Can i have one of the bindings from diffrent control in XAML?
Is below syntax possible? it always return me null as the first binding.
[...] (Updated)rgames on WPF DataGrid – Committing changes cell-by-cellKeith Richardson on Silverlight MultiBindings, How to attached multiple bindings to a single property.Keith Richardson on Silverlight MultiBindings, How to attached multiple bindings to a single [...]
Stefan Olson has updated his enhanced version of this library to work with Silverlight 4: http://www.olsonsoft.com/blogs/stefanolson/post/Updates-to-Silverlight-Multi-binding-support.aspx. Looks like you now have to create a “BindingCollection” type to hold the bindings, rather than just letting them be an ObservableCollection. Thank you Colin and Stefan!
@All,
Updated for SL4 here: http://www.scottlogic.co.uk/blog/colin/2010/05/silverlight-multibinding-solution-for-silverlight-4/
Regards, Colin E.
I’m getting the same error as Florian after I converted to Silverlight 4. Any ideas yet? Thanks.
In Silverligh 4 I get the following exception.
System.ArgumentException: Object of type ‘System.Windows.Data.Binding’ cannot be converted to type ‘System.Collections.ObjectModel.ObservableCollection
@Florian, I’ll try and look into this shortly.
Colin E.
Sorry, some more to add..
First of all, I see this is a big contentious issue, which is sort of hanging in the balance still it seems (maybe Microsofts concreting their implementation of MVVM in 2010 will help).
After reading more of the discussions, I see what Josh Smith suggests is Model-ModelView-View-ViewModel (MMVVVM)
http://joshsmithonwpf.wordpress.com/2008/12/01/the-philosophies-of-mvvm
Horrible name yes, but provides some clarity as to what some view MVVM should be, which I previously pondered.
Essentially what I use are ModelViews, and I use converters instead of ViewModels for formatting etc. I’m still not sold on ViewModels as Josh describes, feel like you code-base will start to be very bloated. Yes, the formatting code is common to the converter and ViewModel, I just feel creating a new ViewModel class with new properties is a bit much, adding another level (think about adding a new property to your Model, bubbling up (or down) you have another layer to add it to?
I will refer to mine as VMs (basically combines Models for a View), and Josh’s as ViewModel and ModelView, to try prevent some confusion.
Typically I have a VM per View (i.e. per Control), which exposes a number of Models. Converters convert the Model properties to a desired format, based on a preferences manager say. If I had multiple Views for a specific VM, I would control the formatting by the converter and the preferences, as opposed to having multiple ViewModels for each. That would lead to having a ModelView per Model, a ViewModel for each Model and View, and another ViewModel per View (which combines the ViewModels per Model & View for each Control)? All a bit confusing…
As others Paul Stovell said, “I see the VM as a way of shaping the domain model, rather than a wayof completely simplifying the view.”
His example: “a library book is overdue, then I might expose a property such as ‘IsOverdue’ which my panel’s visibility is based on.”, and not have a Visibility property in the VM.
Thoughts?
Hi Greg,
Thanks for your comments – I guess as you have discovered for yourself, it was Josh Smith who suggested that the MVVM pattern can be used to totally remove the need for ValueConverters. This is quite an extreme view and I think Josh proposed it in order to stimulate discussion. It has certainly done the trick!
I take a pragmatic approach and will quite often do away with MVVM altogether. WPF / Silverlight has a great binding framework that makes it possible to bind straight to your business objects. If you do not need unit test or designer support, then why use MVVM. I have mentioned this in some of my other posts:
http://www.scottlogic.co.uk/blog/colin/2009/08/the-mini-viewmodel-pattern/
I like the quote from Paul Stovell which you included.
Colin E.
Hi,
From what I have been reading, maybe I’m taking it too literally, but basically says you won’t really use Converters/MultiBinding when using MVVM. This doesn’t ring true with me, so I’m pondering whether I’m implementing MVVM as it should be.
My view of MVVM is to arrange the data in a view friendly way, but without formatting/converting it. So for example, my VM’s expose Models to the View, and I will have a converter to convert their properties to a string say (I’m not saying I convert a whole Model object into the Views “flavour”).
For example, a Statistics class has Lows/Highs/etc. for a product, which is exposed to View via a VM in a collection. The View wants a string to put in a text field, so if I don’t want to use the included type converter from double to string, to do some custom formatting, I use a IValueConverter implementation.
This is where MultiBinding is required for me…
I need, say, two different parameters which govern the formatting to a string of the monetary value, based on the specific instance of Statistics (the trick is, each Statistic instance can be different in the list, e.g. decimal points displayed different per product). Basically some property of the Statistics instance governs the display format. Note that these properties are not something like a hard-coded format string, but rather a property of the product, which the converter uses in it’s “decision” how to build up a format string.
I cannot use ConverterParameter since it is not a DependancyObject i.e. I cannot bind to a DependancyParameter on my Statistics instance which has these formatting properties.
Nor can I use a DependancyParameter on the Converter, since each Statistics instance needs to change this parameter.
For me the only solution is to use MultiBinding, where I can pass the binding source, with the other properties governing formatting in the array to the converter?
My “pondering” is then that maybe the VM should expose a Statistics collection where each have strings instead of decimals say for the values? Which leads to the VM doing the conversion. I can’t say I’m fond of doing that, I believe that to be view specific. If you have multiple Views for this each wanting a different format, then you’d have a property on the VM telling it what the view wants, which I don’t particularly like either.
Am I fundamentally wrong in how I perceive the VM and it’s role? Or is this an actual case where you want MultiBinding when using MVVM?
Appreciate any ones two cents…
Thanks! You definitely set me down the right path. I realized that I always modify the collection within functions/properties of the object, so I created a “dummy” property that’s job was to raise a changed notification and added it as another binding to my multi binding. I never use the value returned by the dummy property, but it make it call the converter, so it updates the values. If I modified the collection outside of the class, I would need to do a bit more work, but this is fine for now. Thanks again!
-Keith
Hello,
Thanks for the excellent contribution to Silverlight. This is working great for me for simple fields, like a string, but I’m having a problem if I try to bind to an observablecollection. I have a class that contains an observable collection among other properties. I would like to bind, for example, a listbox to an observable collection of this class. I can do this and then use multi-binding to bind to a string property in the class and it sees all changes to this property. However, if I bind to the observable collection in that class, it fires the converter one time, but ignores any modifications to the collection. Do you have any idea what is wrong or where to start looking to fix this? Thanks for any help you can provide.
-Keith
Hi Keith,
Bindings for collection types are ‘special’!
Regular, single valued bindings depend on the source implementing INotifyPropertyChanged, collection binding depend on INotifyCollectionChanged. To bind a collection you must use one of the controls that inheirt from ItemsControl and bind the collection to its ItemsSource property. These controls consume the events from the INotifyCollectionChanged interface and can react to items being added / removed. Properties other than ItemsSource cannot be used for collection binding.
To solve your problem, I would create a view model that wraps your collection, reacts to items being added / changed / removed, and creates the value that you require for your binding.
Regards, Colin E.
[...] Silverlight MultiBindings, How to attached multiple bindings to a single property. I am a WPF Disciple Community Credit Winner [...]
Great and very useful article. However, I have a situation where this is not working. It is when I want to bind to e.g. the “Canvas.Left” property. Since this is not a dependencyproperty of the control itself, it will not work.
Any ideas how I could modify / extend your code to get this working?
Hi Remco,
Try the following modification to BindingUtil …
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()); MultiBinding relay = GetMultiBinding(targetElement); relay.Initialise(); // find the target dependency property Type targetType = null; string targetProperty = null; // assume it is an attached property if the dot syntax is used. if (relay.TargetProperty.Contains(".")) { // split to find the type and property name string[] parts = relay.TargetProperty.Split('.'); targetType = Type.GetType("System.Windows.Controls." + parts[0] + ", System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"); targetProperty = parts[1]; } else { targetType = targetElement.GetType(); targetProperty = relay.TargetProperty; } FieldInfo[] sourceFields = targetType.GetFields(dpFlags); FieldInfo targetDependencyPropertyField = sourceFields.First(i => i.Name == targetProperty + "Property"); DependencyProperty targetDependencyProperty = targetDependencyPropertyField.GetValue(null) as DependencyProperty; // bind the ConvertedValue of our MultiBinding instance to the target property // of our targetElement Binding binding = new Binding("ConvertedValue"); binding.Source = relay; targetElement.SetBinding(targetDependencyProperty, binding); }This assumes that if you have an attached property, the type ‘Canvas’ comes before the dot. From this we locate the Canvas Type, and use the part after the dot ‘Left’, to locate the required dependency property. I have tested in in my code by binding the resulting text to the ToolTipService.ToolTip attached property – it works just fine
Regards, Colin E.
Silverlight MultiBindings, How to attached multiple bindings to a single property. – Colin Eberhardt’s Adventures in WPF…
Thank you for submitting this cool story – Trackback from DotNetShoutout…
While it may be possible to use the view-model to do a away with converters this may result in the view-model knowing more about the view than is optimal.
The advantage of using a converter is that it is clearly part of the view and can be customized for each different view of the same view-model.
Hi Doug,
Very good point, and I totally agree. If you view-model become too tightly bound to a single view, you will have to have multiple view-models to support your different ‘skins’
Colin E.