Click here to Skip to main content
Click here to Skip to main content

Silverlight Multi-Binding

, 17 Nov 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
Performing multi-binding in Silverlight.

Screen.GIF

Introduction

Multi-binding is a very important/powerful feature in WPF. It comes in handy when you want to get a single result that depends on multiple inputs. The result is bound to a special logic often implemented inside a 'MultiValueConverter'. So any change to any of the inputs should be manifested in the output result. In Silverlight, this feature is missing!

In this article, I'll show three solutions I came up with, from 'Quick & Dirty' to the 'WPF-look-alike'.

Background

While working on porting a WPF app to Silverlight, I encountered this 'missing feature' issue (which Silverlight programmers are all familiar with...) as Silverlight is only a subset of WPF. Like any other software developer, the first thing I did was to Google it...

After examining the suggested approaches, I came out with these conclusions:

  1. Some of the solutions where too smart/complex for my 'taste'.
  2. The solutions weren't as robust as I hoped.
  3. For example:

    • Lack of support for DependencyObject multi-binding (only FrameworkElement)
    • Lack of RelativeSource in Binding.
  4. The implementation was too far away from the base-line WPF way (in some cases awkward) which makes porting to Silverlight too messy.

So, I thought I'll give it a try and solve it my own way...

Some 'hints' led me to the solutions I came up with:

  1. MS kept excluding this feature throughout all Silverlight versions, which could have been due to two reasons:
    1. MS is indifferent to its developers' needs...
    2. MS 'thinks' that this feature is relatively simple to achieve using the standard available tools.
    3. I found it was more fruitful for me to take the approach that for any algorithmic problem I encounter, there is a simple, elegant, and quick solution, I just need to find it... so I considered the second reason as the 'real' one.

  2. Thinking of the core functionality of multibinding should 'ring' one's bell:
  3. Which standard Silverlight feature has the 'ability' to monitor and respond to property changes? Yes, DependencyProperty! and it's variant AttachedProperty.

  4. New features introduced in Silverlight 5.0:
    • RelativeSource with AncestorType
    • MarkupExtension (in short -'auto' instantiated object (in XAML) that has a return value).

Having these 'hints' in mind, I came out with three solutions:

1. Quick & Dirty

If you have only the multibinding functionality in mind, you can get along with this approach:

  • Construct a 'specialized' class with AttachedProperties matching your input bindings (you can even give these properties meaningful names).
  • Relay any changes of any of these AttachedProperties to a single 'Any...Changed' subroutine on which you will do two things:
    1. Perform your desired multibinding logic.
    2. Update the 'outcome property'.

2. Partial-Elegant

As best practice it is better to seperate multibinding to seperate tasks:

  1. Multi-input-bindings generic 'engine' (for XAML)
  2. Multi-values-into-one logic (usually as an implementation of IMultiValueConverter).

Having that in mind, we can create an 'AttachedProperty' based class (called MultiBindingUtil) that will have any number (for simplicity's sake, the sample has only three pre-defined ones) of Attached Properties for the input bindings (called Binding1 to Binding(n)), AttachedProperty for the Converter, and finally, an AttachedProperty for the result (called MBResult in the sample). Now all we have to do in XAML is to bind the input binding AttachedProperties to whatever we like, supply a converter, and bind the MBResult back to the property we would like to be changed by the multibinding. Inside the multibinding 'engine', just like the previous example, we'll relay any input-binding changes into a single 'Any...Changed' subroutine; only, there, we'll update the MBResult property with the converted result of the supplied converter, using the class's bindings as the input. All is well, except there is a well documented/reported design-time bug occurring in Silverlight when binding an element's property to its own attached property. This bug manifests itself in a very subtle and informative way:

Ms_AttachedPropRef_Bug.JPG

I couldn't find any solution for this 'local-path' issue. If any of you know how to fix it, please share.

3. WPF-Alike

This solution gives a very close XAML look as WPF's multibinding, which in cases of porting might be helpful. Also, it utilizes the new Silverlight 5.0 MarkupExtension support and the previous solution's MultiBindingUtil class. Here we are using a new class of type MarkupExtension called 'MyMultiBinding(Extension)', which has a Content property List<Binding> called (oddly) 'Bindings' and a Converter property of type IMultiValueConverter called (oddly) 'Converter'.

Setting this property as content is done using this attribute:

[ContentProperty("Bindings")]

The actual trick is done inside the MarkupExtension's most significant override method:

override object ProvideValue(IServiceProvider serviceProvider)

We'll do the following actions:

  1. Get the 'target' FrameworkElement:
  2. IProvideValueTarget pvt = 
      serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
    DependencyObject  TargetObject = pvt.TargetObject as DependencyObject ;
  3. 'Attach' to it MultiBindingUtil's bindings properties with matching values of 'our' Bindings list.
  4. for (int i = 0; i < _Bindings.Count ; i++)
    {
        string sDpName="Binding"+(i+1).ToString()+"Property";
        //using reflection to get the DependencyProperty from type/string
        FieldInfo fi = typeof(MultiBindingUtil).GetField(sDpName);
        if (fi==null)
        {
            throw new IndexOutOfRangeException(
              "MultiBindingUtil Max number of binding(3) exceeded");
        }
        DependencyProperty dp = (DependencyProperty)fi.GetValue(null);
        BindingExpressionBase beb = 
          BindingOperations.SetBinding(TargetObject, dp, _Bindings[i]);                   
    }
  5. 'Attach' to it MultiBindingUtil's Converter property with value of 'our' Converter.
  6. TargetObject.SetValue(MultiBindingUtil.ConverterProperty, this.Converter);
  7. Set the return value to Binding (rather than a simple value). This binding will bind to MBResult MultiBindingUtil's attached property(!).
  8. Binding b = new Binding();
    b.Source = TargetObject;
    b.Path =new PropertyPath(MultiBindingUtil.MBResultProperty);
    return b;

Remarks

  1. Solutions 1, 2 should be compatible with Silverlight 4.0.
  2. Solution 3 doesn't work for Style Setter multi-binding.
  3. The Quick & Dirty solution (#1) can help there, like that:

    <Setter Property="mb:MultiBindingReplacement.EpisodeLength" 
            Value="{Binding Path=RangeMilSec}" />
    <Setter Property="mb:MultiBindingReplacement.Scale" 
            Value="{Binding Path=VM.ScaleTransScaleX}" />

    Where MultiBindingReplacement is the name of the special class, and EpisodeLength and Scale are special DependencyPropertys for the bindings.

    Inside the class, I perform the 'conversion logic' and set the result to a special property in the Style's targeted object (as explained in solution 3).

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

ntg123
Software Developer (Senior) self employed
Israel Israel
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 PinmemberPatrick-Wayfarer30-Oct-12 20:49 
GeneralRe: My vote of 5 Pinmemberntg1239-Nov-12 23:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411022.1 | Last Updated 17 Nov 2011
Article Copyright 2011 by ntg123
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid