WPF ToggleButton multibinding of IsChecked through MarkupExtension throws

447 Views Asked by At

I am trying to bind the IsChecked property of a ToggleButton through a markup extension which resolves to a MultiBinding. In XAML I have two source toggle buttons and a target toggle button which should have its IsChecked bound to the IsChecked of the source buttons.

<ToggleButton x:Name="Source1" Content="Source 1" Margin="5" Padding="5,2"/>
<ToggleButton x:Name="Source2" Content="Source 2" Margin="5" Padding="5,2"/>

<ToggleButton Content="Target" Margin="5" Padding="5,2">
    <ToggleButton.IsChecked>
        <local:ExMultiBinding  Converter="{StaticResource AnyConverter}">
            <Binding ElementName="Source1" Path="IsChecked"/>
            <Binding ElementName="Source2" Path="IsChecked"/>
        </local:ExMultiBinding>
    </ToggleButton.IsChecked>
</ToggleButton>

My markup extension providing the MultiBinding looks like this

[ContentProperty("Bindings")]
public class ExMultiBindingExtension : MarkupExtension, INotifyPropertyChanged
{
    public Collection<BindingBase> Bindings { get; set; } = new Collection<BindingBase>();
    public IMultiValueConverter Converter { get; set; }
    public BindingMode Mode { get; set; }
    public UpdateSourceTrigger UpdateSourceTrigger { get; set; }


    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var multi = new MultiBinding
        {
            Converter = Converter,
            Mode = Mode,
            UpdateSourceTrigger = UpdateSourceTrigger
        };
        return multi;
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Starting the UI yields

ArgumentException: 'System.Windows.Data.MultiBinding' is not a valid value for property 'IsChecked'.

I checked and the IsChecked property on the ToggleButton implementation is actually not marked with

[Bindable(true)]

but only with

[Category("Appearance")]
[TypeConverter(typeof (NullableBoolConverter))]
[Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)]

Direct binding through a Binding or MultiBinding in XAML works.

The example code is simplified to highlight the problem. It is not possible to avoid the MarkupExtension in the real code since the implementation is more complicated.

1

There are 1 best solutions below

0
BionicCode On

BindingBase itself is a MarkupExtension. And of course a markupExtension is not of type bool and can't be assigned to a member of type bool.

The reason why your extension is called is because the XAML parser wants to resolve every MarkupExtension. It's done by invoking the MarkupExtension.ProvideValue method. In this case the BindingBase object will be associated with a BindingExpressionBase object. This BindingExpressionBase will resolve the underlying binding to return the actual value (simplified).

So you have to manually resolve the BindingBase markup:

public override object ProvideValue(IServiceProvider serviceProvider)
{
  var multi = new MultiBinding
  {
    Converter = Converter,
    Mode = Mode,
    UpdateSourceTrigger = UpdateSourceTrigger
  };

  // Resolve the MarkupExtension BindingBase
  return multi.ProvideValue(serviceProvider);
}