Silverlight multi-binding for WPF

by StefanOlson 21. July 2009 10:42

In my previous post on Silverlight multi-binding support I mentioned that theoretically it should be possible to use the Silverlight multi-bindings in WPF. Unfortunately the practicalities of single sourcing between WPF and Silverlight are not always as simple as you might expect, and this case was no different!

Given that WPF already has its own multi-binding functionality, why would you want to use the Silverlight attack? You only really want to do this when you want to have source code compatibility between WPF and Silverlight. The updated source code for the Silverlight multi-bindings, which is available below demonstrates this with an application that uses the same source code for both WPF and Silverlight.

So onto the difficulties in making it work for WPF. The first problem is that Colin’s original structure used an ObservableCollection for the bindings:

<local:MultiBinding TargetProperty="Text" Converter="{StaticResource TitleConverter}">
    <Binding Path="Surname"/>                            
    <Binding Path="Forename"/>
</local:MultiBinding>

Unfortunately,WPF will not let you put bindings into an ObservableCollection, so I had to build a new BindingCollection class based on the model used by multi-bindings in WPF.

Once that was solved the larger problem was the fact that objects are created differently from the Xaml/Baml between Silverlight and WPF. This meant the assumptions about the timing of the creation and the completeness of an object at any given time were wrong.  WPF’s Baml reader will create an object, assign it to a dependency property and then fill its attributes. Silverlight’s Xaml reader will create an object, fill it’s attributes and then assign it to the dependency property, a feature the Colin was relying on.

So I had to come up with a completely different solution. What I decided to do was catch the loaded event of the object that we are connected to and at that time I convert the bindings that we have created in to pure WPF multi-bindings as you can see in the code below:

#if !SILVERLIGHT
void Loaded(object sender, RoutedEventArgs e)
{
    _targetElement.Loaded -= Loaded;
    foreach (MultiBinding binding in Bindings)
    {
        FieldInfo field = _targetElement.GetType().GetField(binding.TargetProperty + "Property",
                                                            BindingFlags.Public | BindingFlags.Static |
                                                            BindingFlags.FlattenHierarchy);
        if (field == null) continue;

        System.Windows.Data.MultiBinding newBinding = new System.Windows.Data.MultiBinding
                                                          {
                                                              Converter = binding.Converter,
                                                              ConverterParameter = binding.ConverterParameter
                                                          };
        foreach (BindingBase bindingBase in binding.Bindings)
        {
            newBinding.Bindings.Add(bindingBase);
        }
        
        DependencyProperty dp = (DependencyProperty)field.GetValue(_targetElement);

        BindingOperations.SetBinding(_targetElement, dp, newBinding);
    }
}
#endif

The only tricky part is finding the dependency property that we need to work with - This is a bit of a hack where I search for a static field with the given name and Property appended to it, which is the naming convention for dependency properties.

Using the multi-bindings is still exactly the same as described in the previous post but can now be used on both WPF and Silverlight!

Download Source

you can download the latest source code from here

…Stefan

Tags:

Silverlight | WPF

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

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.

Tag cloud