Improvements to Silverlight Multi-binding support

by StefanOlson 19. July 2009 14:57

Update 29/April/2010: Have changed the examples and updated the zip file to reflect to the changes required for Silverlight 4 compatibility (see here for details).

Hopefully some of you have picked up the recent blog post by Colin Eberhardt, entitled Silverlight MultiBindings, How to attached multiple bindings to a single property.  It provides an excellent basis for multi-binding support in Silverlight until they actually get on with it and become more compatible with WPF and have multi-binding directly built in!

However, when I came to use the multi-binding support, there was a limit with Colin's original design that you can only have one multi-binding per element, as you can see by this example:

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

If you also wanted to hide the text block if forename or surname were empty, under the original design that you couldn't do this, because you can only have one target property. So I've made some changes which allows you to have multiple multi-bindings per element.  So to make the example I'm describing possible the code would now look like this:

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

So, now you can have an unlimited number of multi-bindings on the TextBlock!

Unfortunately, this makes a single multi-binding slightly more complicated because you need to declare the multi-bindings object to contain only a single binding. So the original example, if you were just having a single binding it would look like this:

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

Source Code

you can download the source code for the project here slmultibinding.zip

WPF Compatibility

The code here should (in theory) be compatible with WPF if you want to single source your xaml code between WPF and Silverlight.  Hopefully Silverlight 4 will have multi-binding and this workaround will no longer be required.

…Stefan

Tags:

Silverlight

Comments

7/19/2009 6:28:27 PM #

Hi Stefan,

Nice one - good improvement. Did you also see the little amendment I added at the bottom of the page to allow binding of attached properties:

www.scottlogic.co.uk/.../#comment-2124

Regards,
Colin E.

Colin E.

7/19/2009 7:16:00 PM #

Colin,

Thanks so much for the original article, the lack of multi-binding is extremely frustrating when working in Silverlight.

Yes, I did include the change you made to support attached properties into the code I've used.  I'll be interested to see if anyone needs to use it for properties outside of the System.Windows.Controls that you have referenced. It would be nice to avoid having to hardcode that.

...Stefan

StefanOlson

7/19/2009 11:52:09 PM #

Cool - glad you included that.

Yes, I did wonder about hard-coding the System.Windows.Controls namespace, however it was a compromise (these things always are). To do it properly I think you would have to allow namespace prefixes - I have no idea if the XAML parser exposes the namespace prefix mappings for a document. So, the compromise was just to keep it simple!

Colin E.

Colin E.

12/7/2009 1:12:10 AM #

Thanks for the article.

I can't get the multibindings to work when using more than one source. The bindings do not seem to be updated when specifying a source using ElementName. I adapted the example (to something non-sensical) to illustrate what I want to do. When MyListBox.SelectedItem changes, the bindings aren't updated (breakpoints in the converter aren't encountered).


<TextBlock x:Name="Block" Foreground="White" FontSize="13"
           Margin="5,0,0,0">
    <local:BindingUtil.MultiBindings>
        <local:MultiBindings>
            <local:MultiBinding TargetProperty="Text" Converter="{StaticResource TitleConverter}">
                <Binding Path="Surname" />                            
                <Binding Path="SelectedItem" ElementName="MyListBox"/>
            </local:MultiBinding>
        </local:MultiBindings>
    </local:BindingUtil.MultiBindings>
</TextBlock>


Is this a limitation of the implementation or am I doing something else wrong?

Erik

12/11/2009 8:57:17 PM #

Recently came by this article, and must say that its great! However, I am having a slight problem, although it is obviously one of those "by design" things, but perhaps you'll be able to help me.

I am using the code to format data in a DataGridTemplateColumn in a DataGrid. I have one MultiBinding with two Bindings (so that means two BindingSlave's being created). Once the DataGrid is bound (for simplicity, lets say there's just one row), each of the BindingSlave's Value property changes, and as a result, UpdateConvertedValue is being called twice. However, the first time it is called, the second BindingSlave does not yet have a value (well, it does - the null that is specified in the DependencyProperty ValueProperty) - I dont know the proper terminology, but its basically because it has not yet had its Value assigned. This presents a problem for when writing the Converter - it must account for the cases when the second BindingSlave has no value yet. In essense, that amounts to lots of "==null" checking, which may not be correct in some cases, since it just might be true that the value is null.

For now (i.e. it is enough in my case), I changed the code as follows to work around this:
BindingSlave class:
Change

public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(BindingSlave), new PropertyMetadata(null, OnValueChanged));

to

internal static object ValueProperty_NoValue = new object();
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(BindingSlave), new PropertyMetadata(ValueProperty_NoValue, OnValueChanged));


MultiBinding class:
Change the UpdateConvertedValue method as so:

    private void UpdateConvertedValue()
    {
      var values = new List<object>();
      foreach (BindingSlave slave in Children)
      {
        // if the BindingSlave doesnt have a value yet, dont calculate the ConvertedValue
        var o = slave.Value;
        if(BindingSlave.ValueProperty_NoValue==o)
          return;
        values.Add(o);
      }
      ConvertedValue = Converter.Convert(values.ToArray(), typeof(object), ConverterParameter, CultureInfo.CurrentCulture);
    }


What this does it make sure that the Converter is only called when all the BindingSlaves have had the Value set.
This works in my case, but my case is the OneTime binding mode with nothing special being done by the DataGrid, it just displays data. I'll be glad to see a "fix" for this being done by people with better knowledge than me in Silverlight Smile

Regards,
Anton A.

Anton A.

2/18/2010 7:15:36 PM #

Silverlight multi-binding for WPF

Silverlight multi-binding for WPF

Stefan Olson's Blog

4/19/2010 2:05:18 AM #

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

4/21/2010 2:08:28 PM #

Florian,

Yes, I've noticed that problem to. I will investigate soon and post here, if I can find a solution.

...Stefan

StefanOlson

4/21/2010 6:32:12 PM #

I solved it temporarally by using using the default ContentProperty 'Children' and in xaml using the <BindingSlave /> control instead of <Binding />.

Florian

4/28/2010 10:45:05 AM #

I have now made some changes so that it will work under Silverlight 4, see this post for details:
www.olsonsoft.com/.../...ulti-binding-support.aspx

StefanOlson

8/19/2011 1:02:22 AM #


Hi Stefan,

    I created a modification to your update to Colin's multi-binding.  I added the ability to get a parameter on ConvertBack using a dependency property.  I had a case where this was necessary in order to have a dynamic Dictionary<string, string> that could be bound two-way.
    Please see this article: flyinghighsoftware.wordpress.com/.../ and let me know what you think.

Brian Collins

Add comment




biuquote
  • Comment
  • Preview
Loading



About the author

Stefan Olson is the Managing Director of Olson Software.  He has been developing software using Microsoft Technologies for nearly 20 years.

He is currently working on building the next generation Virtual Tour software in WPF and Silverlight for www.palacevirtualtours.com.