Silverlight MultiBinding updated, adding support for ElementName and TwoWay binding

August 12th, 2010 by Colin Eberhardt

This blog post describes an update to the Silverlight 4 MultiBinding technique I blogged about a couple of months ago to add support for ElementName binding and TwoWay binding.

A few months ago I posted an update to my MultiBinding solution for Silverlight 4. This technique allows you to perform the same kind of multibindings which are possible in WPF, where a property value is bound to multiple sources via a special value converter that implements the IMultiValueConverter interface, which describes how these values are combined. This update proved popular once again, and I received a few requests to add support for ElementName and TwoWay binding. I like challenge! This blog post describes how these two features were implemented, but if you just want to grab the code, you will find the link at the end of this article.

A brief recap

Before I go into the implementation details for the new features I will provide a brief recap of how my multibinding solution works. The XAML for creating a multibinding looks like the following:

<TextBlock Foreground="White" 
  <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="ToolTipService.ToolTip"
                          Converter="{StaticResource TitleConverter}">
        <local:BindingCollection>
          <Binding Path="Surname"/>
          <Binding Path="Forename"/>
        </local:BindingCollection>
      </local:MultiBinding>
    </local:MultiBindings>
  </local:BindingUtil.MultiBindings>
</TextBlock>

Here the Text property and attached ToolTip property of the TextBlock are bound to both the Surname and Forename property of the business object which is set as the DataContext of our view.

The value converter is as follows:

public class TitleConverter : IMultiValueConverter
{
 
  public object Convert(object[] values, Type targetType,
    object parameter, CultureInfo culture)
  {
    string forename = values[0] as string;
    string surname = values[1] as string;
 
    return string.Format("{0}, {1}", surname, forename);
  }
 
  ...
}

In the example below you can see that as you change the forename or surname, the title text and tooltip are updated by the multibinding.

So how does this work?

When a multibinding is created and added to an element via the BindingUtil.MultiBindings attached property, the MultiBinding instance is added to a virtual-branch, this is a branch of the visual tree that obtains the DataContext of the element to which it is bound, but is not added to the visual tree itself. The MultiBinding then creates a BindingSlave instance for each of the given Bindings. These ‘slave’ elements inherit the MultiBinding DataContext and are used to evaluate each of the individual Bindings. The MultiBinding instance aggregate the results of each binding with the IMultiValueConverter used to compute the ConvertedValue property which is bound to the target property on the element to which this MultiBinding as attached.

ElementName binding

So why does the above solution not work if one of the multibindings uses ElementName to locate the source rather than using the inherited DataContext? The problem here is that the MultiBinding and its BindingSlave instances are located in a virtual branch and are therefore not in the same namescope as the target element. As a result, they cannot perform look up of named elements.

In order to solve this problem I created a BindingSlave subclass specifically for ElementName binding. This slave locates the source element named via the ElementName property and sets it as the Source of the binding it uses to compute its Value property.

The only minor complication I encountered is that the MultiBinding might be constructed before the element referenced via ElementName. For this reason the binding slave must handle LayoutUpdated events to ensure that the named element is located if it is constructed after the multibinding.

public class ElementNameBindingSlave : BindingSlave
{
  private FrameworkElement _multiBindingTarget;
 
  /// <summary>
  /// The source element named in the ElementName binding
  /// </summary>
  private FrameworkElement _elementNameSource;
 
  private Binding _binding;
 
  public ElementNameBindingSlave(FrameworkElement target, Binding binding)
  {
    _multiBindingTarget = target;
    _binding = binding;
 
    // try to locate the named element
    ResolveElementNameBinding();
 
    _multiBindingTarget.LayoutUpdated += MultiBindingTarget_LayoutUpdated;
  }
 
  /// <summary>
  /// Try to locate the named element. If the element can be located, create the required
  /// binding.
  /// </summary>
  private void ResolveElementNameBinding()
  {
    _elementNameSource = _multiBindingTarget.FindName(_binding.ElementName) as FrameworkElement;
    if (_elementNameSource != null)
    {
      SetBinding(BindingSlave.ValueProperty, new Binding()
      {
        Source = _elementNameSource,
        Path = _binding.Path,
        Converter = _binding.Converter,
        ConverterParameter = _binding.ConverterParameter
      });
    }
  }
 
  private void MultiBindingTarget_LayoutUpdated(object sender, EventArgs e)
  {
    // try to locate the named element 
    ResolveElementNameBinding();
  }
}

The example below demonstrates element name binding by binding the Value of two Slider elements to a TextBlock which displays the sum of the two values.

<TextBlock Grid.Column="1">
  <local:BindingUtil.MultiBindings>
    <local:MultiBindings>
      <local:MultiBinding TargetProperty="Text"
                          Converter="{StaticResource SliderValueConverter}">
        <local:BindingCollection>
          <Binding ElementName="sliderOne" Path="Value"/>
          <Binding ElementName="sliderTwo" Path="Value"/>
        </local:BindingCollection>
      </local:MultiBinding>
    </local:MultiBindings>
  </local:BindingUtil.MultiBindings>
</TextBlock>
 
<Slider x:Name="sliderOne" Value="10"/>
 
<Slider x:Name="sliderTwo"  Value="20"/>

Here is the value converter that is used to compute the sum:

public class SliderValueConverter : IMultiValueConverter
{
 
  public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    if (values.Length != 2 ||
        values[0] == null ||
        values[1] == null)
      return null;
 
    return (double)values[0] + (double)values[1];
  }
 
  ...
}

You could of course use element name binding to combine the surname / forename in the first example in this blog post, but in this context it is more likely that you will want to back your UI with a business object. It is also possible to mix element name and regular (i.e. Source=DataContext) binding.

I find multibindings which use ElementName references most useful when creating complex UI layouts that do not lend themselves to being implemented using Panels. For a good example see my article on the implementation of a BulletGraph control which makes extensive use of this technique in order that the layout of the control is performed entirely within XAML.

TwoWay Binding

A two-way multibinding must be able to handle updates to the combined value and split it up into its constituent parts in order to update the multiple source bindings. In the first example where a forename and surname property are combined into a “surname, forename” string it is possible to convert back the other way, but in the example above where the values of two Sliders are combined a reverse conversion is not possible.

Modifying this multibinding solution to permit two way binding was relatively straightforward. A property changed event handler was added to the MultiBindig.ConverterValue (which is bound to the multi binding target) so that we can determine when changes have been made. This handler then uses the IMultiValueConverter to convert the value into the multiple source properties and updates the binding slaves accordingly:

/// <summary>
/// Handles property changes for the ConvertedValue property
/// </summary>
private void OnConvertedValuePropertyChanged()
{
    OnPropertyChanged("ConvertedValue");
 
    // if the value is being updated, but not due to one of the multibindings
    // then the target property has changed.
    if (!_updatingConvertedValue)
    {
      // convert back
      object[] convertedValues = Converter.ConvertBack(ConvertedValue, null,
          ConverterParameter, CultureInfo.InvariantCulture);
 
      // update all the binding slaves
      if (Children.Count == convertedValues.Length)
      {
        for (int index = 0; index < convertedValues.Length; index++)
        {
          ((BindingSlave)Children[index]).Value = convertedValues[index];
        }
      }
    }
}

In order to use two way multibinding both the multibinding mode and the bindings within the BindingCollection must be set to TwoWay. See the example given below:

<TextBlock Text="Surname:"/>
<TextBox  Grid.Column="1" Text="{Binding Path=Surname, Mode=TwoWay}"/>
 
<TextBlock Grid.Row="1" Text="Forename:"/>
<TextBox Grid.Row="1"  Grid.Column="1" Text="{Binding Path=Forename, Mode=TwoWay}"/>
 
<TextBlock Grid.Row="2" Text="Combined:"/>
<TextBox Grid.Row="2"  Grid.Column="1" >
  <local:BindingUtil.MultiBindings>
    <local:MultiBindings>
      <local:MultiBinding TargetProperty="Text"
                        Converter="{StaticResource TitleConverter}"
                        Mode="TwoWay">
        <local:BindingCollection>
          <Binding Path="Surname" Mode="TwoWay"/>
          <Binding Path="Forename" Mode="TwoWay"/>
        </local:BindingCollection>
      </local:MultiBinding>
    </local:MultiBindings>
  </local:BindingUtil.MultiBindings>
</TextBox>

You can have try of two way multibinding below where the values of the forename and surname text boxes are combined in the box below. However, you ca also make updates to the combined result which will then be converted back into its constituent parts:

And here is the value converter:

public class TitleConverter : IMultiValueConverter
{
  #region IMultiValueConverter Members
 
  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);
  }
 
  public object[] ConvertBack(object value, Type[] targetTypes,
    object parameter, System.Globalization.CultureInfo culture)
  {
    string source = value as string;
    var pos = source.IndexOf(", ");
 
    string forename = source.Substring(pos + 2);
    string surname = source.Substring(0, pos);
 
    return new object[] { forename, surname };
  }
 
  #endregion
}

So, there you have it, two-way and element name multibinding :-)

You can download the full source, including a WPF build (thanks to Stefan Olson) here: SLMultiBindingUpdated.zip

Now … go forth and multibind.

Regards, Colin E.

Tags: , , , ,

66 Responses to “Silverlight MultiBinding updated, adding support for ElementName and TwoWay binding”

  1. Davis Ford says:

    If you happen to be using multibinding inside a DataGridTemplateColumn.CellTemplate like me, then you need to adjust the code slightly, so that the inner cell template FrameworkElement can walk up the visual tree and find the parent binding outside of the DataGrid itself. I updated the method “ResolveElementNameBinding” in MultiBinding.cs to make this work as follows:

    private void ResolveElementNameBinding()
    {
    _elementNameSource = _multiBindingTarget.FindName(_binding.ElementName) as FrameworkElement;

    if (_elementNameSource == null)
    {
    var obj = VisualTreeHelper.GetParent(_multiBindingTarget);
    while(obj != null)
    {
    var fe = obj as FrameworkElement;
    if (fe == null) continue;
    _elementNameSource = fe.FindName(_binding.ElementName) as FrameworkElement;
    if (_elementNameSource != null)
    break;
    obj = VisualTreeHelper.GetParent(obj);
    }
    }
    if (_elementNameSource != null)
    {
    SetBinding(BindingSlave.ValueProperty, new Binding()
    {
    Source = _elementNameSource,
    Path = _binding.Path,
    Converter = _binding.Converter,
    ConverterParameter = _binding.ConverterParameter
    });
    }
    }

  2. Matt says:

    I believe I may have found a bug with using this in a SL5 project. I am (through C# code) creating two standard bindings, adding both of them to the binding collection in a MultiBinding, and then adding the MultiBinding to the MultiBindings’ list of MultiBindings (phew!). I also I have a IMultiValueConverter assigned to the MultiBinding. I initialized the binding on three different rectangle objects with respect to their visibility properties. Anyway, when the ValueConverter gets called it isn’t until the third call that the value is what it should be. I’ve attempted a few other combinations to see if it was something I was doing. I also tested against just a regular Binding on each of the rectangles with a similar ValueConverter an the values passed in are correct.

  3. Hi Colin,

    thanks for a useful MultiBinding solution.

    I recently published an alternative Silverlight 5 MultiBinding solution with support for markup extension syntax, two-way binding and support for RelativeSource and ElementName. It also supports bindable StringFormat, Converter and ConverterArguments. This solution is described in The Code Project article “MultiBinding in Silverlight 5″ found at http://www.codeproject.com/KB/silverlight/SilverlightMultiBinding.aspx.

    In contrast to your MultiBinding solution I used attached properties on the target element to store the individual source bindings. In this way bindings relative to the DataContext, named elements (ElementName) and RelativeSource are supported. However, my solution does not support Silverlight 4.

  4. J says:

    To fix the FindName issue not finding the correct element, I have used this code and it seems to fix the issue:

    ///
    /// Try to locate the named element. If the element can be located, create the required
    /// binding.
    ///
    private void ResolveElementNameBinding()
    {
    DependencyObject parent = _multiBindingTarget;

    while (parent != null && _elementNameSource == null)
    {
    _elementNameSource = ((FrameworkElement)parent).FindName(_binding.ElementName) as FrameworkElement;
    parent = VisualTreeHelper.GetParent(_multiBindingTarget);
    }

    if (_elementNameSource != null)
    {
    SetBinding(BindingSlave.ValueProperty, new Binding()
    {
    Source = _elementNameSource,
    Path = _binding.Path,
    Converter = _binding.Converter,
    ConverterParameter = _binding.ConverterParameter
    });
    }
    }

    • J says:

      Oops.. to quick to post.

      Here is the real one

      ///
      /// Try to locate the named element. If the element can be located, create the required
      /// binding.
      ///
      private void ResolveElementNameBinding()
      {
      DependencyObject parent = _multiBindingTarget;
      _elementNameSource = _multiBindingTarget.FindName(_binding.ElementName) as FrameworkElement;

      while (parent != null && _elementNameSource == null)
      {
      _elementNameSource = ((FrameworkElement)parent).FindName(_binding.ElementName) as FrameworkElement;
      parent = VisualTreeHelper.GetParent(parent);
      }

      if (_elementNameSource != null)
      {
      SetBinding(BindingSlave.ValueProperty, new Binding()
      {
      Source = _elementNameSource,
      Path = _binding.Path,
      Converter = _binding.Converter,
      ConverterParameter = _binding.ConverterParameter
      });
      }
      }

  5. pd says:

    Hi
    I want to use this as Command parameter of a button.currently i am using something like this

    It is showing some error “A property element can not be direct content of another property element”. I am new to silverlight. please help me. Thanks

    • TSouthwick says:

      Not sure if you figured this out, but I was having the same issue. For instance, I was using it to set the Foreground property of ProgressBar. This produces the error:

      ….multibinding stuff…..

      I changed it to:

      ….multibinding stuff with TargetProperty=”Foreground”…..

      Just in case someone else had this issue, they won’t be stuck for an hour like I was!

  6. Bill Thorp says:

    I don’t see any copy-left information on this. It seems a number of people are using this code, could you officially slap a license on it? (CC/MIT/Apache/LGPL preferred.) Thank you, this is great stuff!

  7. anatoly says:

    hello,
    i’m try to use this extension in my project, but have some trouble:
    i have xaml like this (simplified for example)

    but in my converter i always recieve array of two items: null and somePE

    when i try to search problem i find that
    _elementNameSource = _multiBindingTarget.FindName(_binding.ElementName) as FrameworkElement;

    in MultiBinding.cs

    always return null… i try find my element by name in this place, try to find parent with VisualTreeHelper, try to use FrameworkElement.Parent property but always have null

    anybody know how to solve this problem?

  8. Now that Silverlight 5 Beta is out with support for RelativeSource in bindings, is there any chance of updating MultiBinding to support it?

  9. Seb says:

    Hi,

    verry good job ! I notice that exception is raised (I see it in Output window) even if the code seems work perfectly :

    Erreur System.Windows.Data : le convertisseur ‘MS.Internal.Data.DynamicValueConverter’ n’a pas pu convertir la valeur ‘null’ (type ‘null’); BindingExpression : Path=’ConvertedValue’ DataItem=’BPVF.Commun.MultiBinding’ (HashCode=54411269); l’élément cible est ‘System.Windows.Controls.Button’ (Name=”); la propriété cible est ‘IsEnabled’ (type ‘System.Boolean’).. System.InvalidOperationException: Impossible de convertir le type null en type System.Boolean.
    à MS.Internal.Data.DynamicValueConverter.Convert(Object value, Type targetType, Object parameter, CultureInfo culture)
    à System.Windows.Data.BindingExpression.ConvertToTarget(Object value).

    Do you have any idea how to fix it ? It seems occur because target type is no nullable.

    Regards,

  10. Mark says:

    Just a quick thank you here for a useful piece of shared code.

    • Mark says:

      In trying to bind the control to multiple DomainDataSource loads, like the previous comment below some do come back null:

      System.Windows.Data Error: ‘MS.Internal.Data.DynamicValueConverter’ converter failed to convert value ‘null’ (type ‘null’);
      BindingExpression: Path=’ConvertedValue’ DataItem=’RoasterWerks.MultiBinding’ (HashCode=61830130);
      target element is ‘RoasterWerks.Controls.BusyIndicator’ (Name=’bi_BusyIndicator’);
      target property is ‘IsBusy’ (type ‘System.Boolean’)..
      System.InvalidOperationException: Can’t convert type null to type System.Boolean.
      at MS.Internal.Data.DynamicValueConverter.Convert(Object value, Type targetType, Object parameter, CultureInfo culture)

  11. Kenrae says:

    Just thought I’d report you a bug I’ve found.

    You solution doesn’t work with attached properties from a custom control (or any other class not in System.Windows.Controls). To be precise, something like this:

    TargetProperty=”controls:VideoPlayerControl.IsOneSignal”

    doesn’t work.

    The culprit is this piece of code on MultiBindings.cs:

    // 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];
    }

    Since in the particular case I am I can use another approach easily, I’ll just do that, but I thought you’d be interested to be aware of the problem.

    Otherwise, it’s a fine solution.

    Greetings,
    -Sergi Díaz

  12. Kunal says:

    Hi,

    There was a little modification required under your code.[MultiBinding.cs] -> private void ResolveElementNameBinding()

    Problem: Your ElementBinding working fine but it fails or i should say it goes in infinite event triggering [ _multiBindingTarget.LayoutUpdated += MultiBindingTarget_LayoutUpdated;]
    when, you try to assign a value to a Label or textblock and it makes usage of Bindings type of= ElementType. And these Elements also makes use of some other ElementType bindings. Then problem occours.

    Although ur code works on textbox but not on textblock,labels…I dont know why.

    What i Did ?
    ——————–
    private void ResolveElementNameBinding()
    {
    _elementNameSource = _multiBindingTarget.FindName(_binding.ElementName) as FrameworkElement;
    if (_elementNameSource != null)
    {
    SetBinding(BindingSlave.ValueProperty, new Binding()
    {
    Source = _elementNameSource,
    Path = _binding.Path,
    Converter = _binding.Converter,
    ConverterParameter = _binding.ConverterParameter
    });
    _multiBindingTarget.LayoutUpdated -= MultiBindingTarget_LayoutUpdated;
    }
    }

    I removed the registered event in the end.

    and now its working fine.

  13. Aleah says:

    I have been unable to make this work in my Silverlight 4 solution. My converter gets called with 2 values but the second value is always null. I’m using this in a datagrid that’s bound to objects. I’ve tried just a simple 2 ints in the object and more complicated 1 int from the object and another property from my viewmodel. The second value is always null.

    • Aleah says:

      It works fine outside of my DataGrid. Do I need to do something differently inside a grid?

    • Mark says:

      I’m getting the null on second value as well .. I’m on a dataform.

    • mikexu says:

      I have some problem in ListBox,does anyone give a resolved.

    • Evgeni says:

      Have the same problem with radio button. In my scenario, I has – two bool source properties: IsAvailable and IsEnabled. I want to set IsEnabled property of the radioButton based on these two values.

      My XAML:

      My Converter:

      public class IsEnabledConverter : IMultiValueConverter
      {
      public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
      {
      bool isAvailable = (bool)values[0];
      bool isEnabled = (bool)values[1];

      if(!isAvailable)
      return false;

      return isEnabled;
      }

      public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
      {
      throw new NotImplementedException();
      }
      }

      The second value is always null (even if I switching order of bindings)

  14. Is it possible for me to do multiple binding on different sources, one is element name and the other one is from a property of a VM.
    Here’s my code

    I tried this one but I always get a null on the second value in the converter.

  15. RPTNNN says:

    Hello, I’m trying to use this as for binding radiobuttons ischecked status.
    I will explain a little my situation:
    I have a group of 4 radiobuttons loaded from a hash table, I then use this multibinding to set the ischecked status depending on the id of the radiobutton (key of the hash-table) and the value selected from a database that indicates which one should be checked.
    This way works fine.
    But I’m having problems with the convertback, where i’m getting as value parameter true or false and the other params are just null.
    Could someone make it clear for me why is it that way and if I have any chance to translate those false and true to the selected radiobutton?
    thanks

  16. Jeff Yates says:

    This is fantastic. Just one small grumble; it doesn’t compile with Warnings as Errors because _collectionChangedCallback in BindingCollection is never assigned.

    Posted this against the wrong blog before, sorry about that.

  17. Craig says:

    I don’t understand why you are creating your own MultiBinding class when there already is one that comes with the framework –
    http://msdn.microsoft.com/en-us/library/system.windows.data.multibinding%28VS.85%29.aspx

    Am I missing something here?

  18. Ryan says:

    Colin,

    My thanks for the tool, however I’m having a very frustrating issue. I’m using multibinding to customize a calendar control. I need some data on each day, and the way I’m doing that is to bind a text field to the date of that calendar and an ObservableCollection of data. Then in the VC, I grab the correct numbers for that date and return it.

    Everything sets up fine initially, but the multibinding seems to completely ignore PropertyChanged events for my ObservableCollection. I’ve thrown the PropertyChanged event for the collection, and the internal objects which are changing, but neither seem to get picked up. The value converter does fire when I change the dates on the calendar (such as navigating to another month), but not for my OC. Any ideas of what to try would be great.

  19. AbdouMoumen says:

    Oh! thanks a lot for that! I’ve been looking for a workaround for quite some time!
    Works great, really helpful :)

  20. Naoma Houff says:

    Greetings I recently finished going through through your blog and also I’m very impressed. I do have a couple concerns for you personally however. Do you consider you’re thinking about doing a follow-up posting about this? Will you be planning to keep bringing up-to-date as well?

    • Hi,

      I have already updated this code a couple of times. If a new version of SL is release, or bugs are found, I plan to release updates. I know that this is quite a popular solution to the problem!

      Regards, Colin E.

  21. HC says:

    Hi Colin,

    very good work, i like this functionality.

    I found one case that multibinding don’t work in the expected way.

    In this case because the DataContext isn’t used, the UI don’t present the label with the value. I fix that situation changing a little the Initialise method of the class MultiBinding.

    Here is the method changed:

    internal void Initialise(FrameworkElement targetElement)
    {
    Children.Clear();
    bool hasDataContextBindings = false;
    foreach (Binding binding in Bindings)
    {
    BindingSlave slave;

    // create a binding slave instance
    if (!string.IsNullOrEmpty(binding.ElementName))
    {
    // create an element name binding slave, this slave will resolve the
    // binding source reference and construct a suitable binding.
    slave = new ElementNameBindingSlave(targetElement, binding);
    }
    else
    {
    slave = new BindingSlave();
    slave.SetBinding(BindingSlave.ValueProperty, binding);
    }

    if (binding.Source == null)
    {
    hasDataContextBindings = true;
    }
    slave.PropertyChanged += SlavePropertyChanged;
    Children.Add(slave);
    }

    if(!hasDataContextBindings) UpdateConvertedValue();
    }

    • Thanks HC,

      Unfortunately your XAML was stripped by the blog software – any chance you could repost, changing the < > brackets to []?

      • HC says:

        Hi,

        There is the xaml with brackets to [] changed.

        [sdk:Label Style="{StaticResource LabelStyle}"]
        [MultiBinding:BindingUtil.MultiBindings]
        [MultiBinding:MultiBindings]
        [MultiBinding:MultiBinding TargetProperty="Content"
        Converter="{StaticResource StringFormatConverter}"]
        [MultiBinding:MultiBinding.Bindings]
        [MultiBinding:BindingCollection]
        [Binding Source="{StaticResource ResourcesStrings}" Path="FinancialHealthResource[MyFinancialHealth]“/]
        [Binding Source="{StaticResource WebContext}" Path="User.Currency" /]
        [/MultiBinding:BindingCollection]
        [/MultiBinding:MultiBinding.Bindings]
        [/MultiBinding:MultiBinding]
        [/MultiBinding:MultiBindings]
        [/MultiBinding:BindingUtil.MultiBindings]
        [/sdk:Label]

  22. Kasim Husaini says:

    Hi Colin,

    I liked both of your solutions regarding data binding
    http://www.scottlogic.co.uk/blog/colin/2009/02/relativesource-binding-in-silverlight/
    and
    http://www.scottlogic.co.uk/blog/colin/2010/08/silverlight-multibinding-updated-adding-support-for-elementname-and-twoway-binding

    I want to add both of these features into one. i.e. I want to bind to a single property of a control, multiple parameters, first parameter is from control’s datacontext while other parameter comes from a relative elements datacontext. Can you guide me on how I can achieve the same.

    Again thanks for excellent solutions.. It really helped me a lot.

  23. Sergey says:

    Hi Colin, tnx for sharing your work.
    I’ve downloaded a sample and it works fine, but after some steps the behavoir is strange.
    I’ve changed PageTwo.xaml to: http://www.everfall.com/paste/id.php?d8ad5ftu2i2u
    also I’ve corrected SliderValueConverter. The Convert func just return string.Empty.

    The strange is that, when we change the sliders the Convert function is called.
    Do I use your MultiBinding the right way? Tnanks in advance.

    p.s. please delete my previous comment

  24. kakone says:

    Hello,

    Very thanks for this article. It’s an excellent work.

    I had an little issue. In some cases, my multibinding didn’t work. I corrected the bug in the MultiBinding class: I added the call to the UpdateConvertedValue method at the end of the Initialise method. Indeed, when you set the bindings to the BindingSlave objects, the SlavePropertyChanged method can’t be called because you subscribe to the PropertyChanged event after that. So, by adding a call to the UpdateConvertedValue method at the end of the Initialise method, it works well.

    Thanks,
    Cordially,
    Kakone

  25. I like the solution, pretty smart and you have managed to get it done in a very elegant form.
    Also this works pretty well, I have used this to implement different column formatting on a DataGrid columns, using multibinding to assign two data values to a column, one for the value and other for the format. It works like a charm.

    Thanks for the great effort with the Multibinding, i really solves many scenarios.

    The only issue I am having is when there is an update of a cell, there you have to put TwoWay on both parameters when I need only the value to change… so I have no way of knowing what format did I apply as the converter is the same for all the values… so by now the only solution is to reset it to a “generic number” by now…

    What would you propose to do to solve this issue / scenario?

    • Hi,

      Sounds complicated! How about using a ConverterParameter to indicate the formatting required? Do you really need to use a MultiBinding?

      Alternatively, you might need to add a ViewModel to perform this complex logic.

      Colin E.

      • Hi Colin,
        Thanks a lot (seriously) for the quick reply!!
        I needed your solution as the format on the cell depends on the information group so it is dynamic and bound to a field named RowNumericFormat, so the data decides how it is formated to…
        Obviously, If I could bind the ConverterParameter or the StringFormat, that would be easier… but as SL is now (V.4.0) your solution is the only I have found to work properly.

        Just for the ones being curious, the complicated logic is done on the ViewModel as you say, the result is the data that is bound. The View just formats it as it is received.

        The xaml for each of the 35 cells is like this:

        A bit too much XAML but it works perfectly!
        Thanks Colin!!

  26. @Jonathan, SilverlightDevelopper,

    Thanks guys, I am glad it helped!

    Colin E.

  27. Espen says:

    First of all…nice work. I have a problem though. Could it be that if one of the bindings is bound to a observablecollection, when an item is deleted from the collection it doesn’t actually rebind? I have pretty nasty binding scenario going on here, and it’s only working initially, but deleting an item in the collection doesn’t rebind. Adding one seems to work though. It’s pretty weird to be honest.

    There’s definitely an issue with the elementnamebinding though. Have a look here: http://pastebin.com/jFMWy0Vm . The whole purpose of that ItemsControl is to visualize a collection and the items in it are rectangles with a number depending on the index in the collection. If you have a look at the ItemTemplate, you’ll see that I have to use the Tag property as the multibinding you made can’t resolve that for some reason. When an item is deleted, the rectangle is removed from the ItemsControl, but the multibinding isn’t updated on the other rectangles, so all in all it works more like a one time binding (a change in the underlying collection the Tag is bound to should trigger the binding shouldn’t it?). Could be that the scenario is hard to achieve though.

  28. YESS!!! Thanks alot! Do you have a donate button? I want to give you a beer.

  29. Daniel Demmel says:

    I managed to reproduce the error with a simple modification of the example Silverlight XAML.

    http://dl.dropbox.com/u/100064/PageTwo.xaml

    Any ideas?

  30. Daniel Demmel says:

    Hey,

    this thing is brilliant, exactly what I was looking for :)

    When trying to adapt the slider example however I`m getting “Unhandled Error in Silverlight Application Layout cycle detected. Layout could not complete.” and no other information..

    Is it possible to use it for binding the width and height of a single layout element?

    Thanks

    • @Daniel,

      A layout cycle is where the layout algorithm is in a loop, i.e. one aspect of the layout depends on another, which in turn depends on the original aspect. Binding width directly to height will always result in a cycle!

      Colin E.

  31. SilverlightDevelopper says:

    Hi again.

    I just wanted to notice you that your solution works perfectly well ^^ thank you !

  32. SilverlightDevelopper says:

    Well, if I may interject, I am currently developping an MVVM app and, in depends of the context.

    First of all, Colin, you’re the man ! ^^ I’m gonna try this ASAP.

    In my context of usage, the multibinding is used to format dynamicaly the datas exposed in a way the UI needs it, and ONLY the UI (another UI would maybe display it differently, not needing the converter). More than useful, in a strictly conceptional view, a ViewModel should expose the datas almost as raw datas, and your UI should format them the way it needs them to be. That’s where I began to search for a two way multibinding.

    In my case, my model inherits from a NotifyPropertyBase so it notifies the UI for every changes made, letting my ViewModel taking care of commands or strange formating / expositions.

    I may be wrong, at least to you @Collin and @Erniel. I’d like to ear your thinking about this view.

    I’ll get back to you as soon as I tested your new solution =D

  33. @Emiel,

    Thanks for your comment, you make an interesting and valid point :-)

    Yes, I would agree that if you have already built an MVVM application and need to perform a “surname, forename” style formatting, then yes, the ViewModel would be the place to do this. However, it is not mandatory that Silverlight applications are built with the MVVM pattern.

    There are occasions where lightweight direct to business object binding is appropriate, when unit testing or designer / developer workflow are not required. In this case, it would be a shame to be forced into creating a ViewModel because of a lack of multibinding in Silverlight.

    Personally, I have found multibinding to be more useful in purely UI binding contexts, check out the article I wrote on Bullet Graphs control development:

    http://www.codeproject.com/KB/WPF/WpfWinFormsBulletGraphs.aspx

    Again, thanks for your comments. I think Silverlight developers should think about whether MVVM is appropriate for their application, and if so, my solution is redundant. However, if MVVM is not appropriate, this multibinding solution is a useful tool for the toolbox.

    Regards, Colin E.

  34. Emiel says:

    I like the technique of the solution, but my problem is on a more conceptual level: shouldn’t these kind of business rules be implemented in the ViewModel instead of in ValueConverters?
    When implemented in the ViewModel, you could just bind to the Title property and implement whatever logic you’d wish to determine the value. If for some reason you would like to include the middle name as part of the title, you would only have to change the view model, instead of changing all the views that use the Title property.

  35. Silverlight MultiBinding updated, adding support for ElementName and TwoWay binding | Colin Eberhardt’s Adventures in WPF…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

  36. [...] Silverlight MultiBinding updated, adding support for ElementName and TwoWay binding [...]

Leave a Reply