Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested MultiBinding(s)

I've been playing around with WPF for quite a while now, but for the first time today, I needed to nest a MultiBinding inside another, something like:

<MultiBinding>
   <Binding />       
   <MultiBinding>
      <Binding />
      <Binding />
   </MultiBinding>
</MultiBinding>

I get an exception indicating it's not allowed by the framework:

XamlParseException was unhandled: Add value to collection of type 'System.Collections.ObjectModel.Collection(System.Windows.Data.BindingBase)' threw an exception.

The InnerException is more explicit:

BindingCollection does not support items of type MultiBinding. Only Binding is allowed.

So digging the web for more info, I stumbled upon this Microsoft Connect issue which is exactly my problem.

Thank you for the feedback. WPF doesn't support this today. This feature has been requested for years (most recently earlier this month - see https://connect.microsoft.com/WPF/feedback/details/650164/nested-multibinding). We'll continue to consider this for future releases.

Right now I've made my peace that I won't have it easy. Still I need this, how can I nest MultiBindings?

like image 512
Louis Kottmann Avatar asked Apr 23 '12 12:04

Louis Kottmann


4 Answers

If you have a converter that takes a parameter, you can do something like this:

  • Create a class for passing the "fixed" data to your converter
  • Add DependencyProperties to the class (so that you can bind the values in Xaml)
  • In your xaml, use a binding with a converter instead of a multibinding, something like this:

    <MultiBinding>
        <Binding Source="SomeObject" Path="CoreValue" Converter="{StaticResource YourNewConverter}">
            <Binding.ConverterParameter>
                <ns:ParameterClass Value1="{Binding Parameter1}" Value2="{Binding Parameter1}" />
            </Binding.ConverterParameter>
        </Binding>
     .... 
    

The limitation is that (AFAIK) the value will only be recalculated if CoreValue changes - it won't automatically rebind if the converter parameters change.

(Apologies for any errors, I'm typing this without the benefit of VS to test in...)

like image 146
Dan Puzey Avatar answered Nov 17 '22 11:11

Dan Puzey


An alternative to the other suggestions is to use attached properties to hold nested MultiBindings as intermediate values.

For example, instead of:

<Element>
  <Element.Property>
    <MultiBinding>
      <Binding Path="A" />       
      <MultiBinding>
        <Binding Path="B" />
        <Binding Path="C" />
      </MultiBinding>
    </MultiBinding>
  </Element.Property>
</Element>

...do this:

<Element Name="ElementName">
  <ElementProperties.AttachedProperty>
    <MultiBinding>
      <Binding Path="B" />
      <Binding Path="C" />
    </MultiBinding>
  </ElementProperties.AttachedProperty>
  <Element.Property>
    <MultiBinding>
      <Binding Path="A" />       
      <Binding ElementName="ElementName" Path="(ElementProperties.AttachedProperty)" />
    </MultiBinding>
  </Element.Property>
</Element>

I know this question is more than six years old now, but I ran into it so someone else will, too.

like image 26
Matt Thomas Avatar answered Nov 17 '22 12:11

Matt Thomas


I know that this is an old question but I think this this is a much nicer approach:

<FrameworkElement x:Name="IsBuyAndAmountInReference">
    <FrameworkElement.Tag>
        <MultiBinding Converter="{StaticResource LogicAndToBool}">
            <Binding Path="OrderData.IsBuy" />
            <Binding Path="OrderData.AmountInReference" />
        </MultiBinding>
    </FrameworkElement.Tag>
</FrameworkElement>
<FrameworkElement x:Name="IsSellAndAmountInBase">
    <FrameworkElement.Tag>
        <MultiBinding Converter="{StaticResource LogicAndToBool}">
            <Binding Path="OrderData.IsBuy" Converter="{StaticResource BooleanToBooleanInvert}" />
            <Binding Path="OrderData.AmountInReference" Converter="{StaticResource BooleanToBooleanInvert}" />
        </MultiBinding>
    </FrameworkElement.Tag>
</FrameworkElement>

<Slider Grid.Row="2" Grid.ColumnSpan="4">
    <Slider.Visibility>
        <MultiBinding Converter="{StaticResource LogicOrToVisibility}">
            <Binding ElementName="IsBuyAndAmountInReference" Path="Tag" />
            <Binding ElementName="IsSellAndAmountInBase" Path="Tag" />
        </MultiBinding>
    </Slider.Visibility>
</Slider>
like image 22
GoLDie Avatar answered Nov 17 '22 11:11

GoLDie


I realise that this is an old question now, but I just hit exactly the same problem as the OP. Fortunately in my case I could bind to a sub-element where the result of the multi-binding was already being calculated, but it got me thinking...

A (though admittedly not very clean) solution would be to write the value of the multi-value binding into a 'spare' property such as an element's 'Tag' which you can then reference in your other multi-value bindings by specifying the 'ElementName' attribute.

If you need more than a single nested multi-value binding then you could create a 'fake' object with some dependency properties on it to store multiple intermediate results.

A pity that Microsoft don't implement a properly nested system...

like image 4
Wolfshead Avatar answered Nov 17 '22 12:11

Wolfshead