C# WPF IsEnabled using multiple bindings?

Viewed 54378

I have a WPF xaml file describing a section of a GUI and I'd like the enabling/disabling of a particular control to be dependent on two others. The code looks something like this at the moment:

<ComboBox Name="MyComboBox"
          IsEnabled="{Binding ElementName=SomeCheckBox, Path=IsChecked}"/>

But I'd like it to be dependant on another checkbox as well so something like:

<ComboBox Name="MyComboBox"
          IsEnabled="{Binding ElementName=SomeCheckBox&AnotherCheckbox, Path=IsChecked}"/>

What's the best way to go about that? I can't help feeling I'm missing something obvious or going about this the wrong way?

5 Answers

As extension to qqbenq's answer:

Added the function to handle the Count of a Collection for example if you want to check if some item of a ListView is selected.

Converter:

public class IsEnabledConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        foreach (var value in values)
        {
            switch (value)
            {
                case bool b when !b:
                case int i when i == 0:
                    return false;
            }
        }

        return true;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        return null;
    }
}

Namespace <theNamespace:IsEnabledConverter x:Key="IsEnabledConverter"/>

Button

<Button x:Name="MyButton">
    <Button.IsEnabled>
        <MultiBinding Converter="{StaticResource IsEnabledConverter}">
            <Binding ElementName="MyListView" Path="SelectedItems.Count"/>
            <Binding ElementName="MyCheckBox" Path="IsChecked"/>
        </MultiBinding>
    </Button.IsEnabled>
</Button>

When you don't want to use MultiBinding

public class AndEnabledTextBox : TextBox
{
    public static readonly DependencyProperty AndEnabled1SubProperty =
        DependencyProperty.Register(nameof(AndEnabled1), typeof(bool), typeof(AndEnabledTextBox), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnAndEnabledPropertyChanged)));
    public static readonly DependencyProperty AndEnabled2SubProperty =
        DependencyProperty.Register(nameof(AndEnabled2), typeof(bool), typeof(AndEnabledTextBox), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnAndEnabledPropertyChanged)));
    public bool AndEnabled1 { get { return (bool)GetValue(AndEnabled1SubProperty); } set { SetValue(AndEnabled1SubProperty, value); } }
    public bool AndEnabled2 { get { return (bool)GetValue(AndEnabled2SubProperty); } set { SetValue(AndEnabled2SubProperty, value); } }
    protected override void OnInitialized(EventArgs e)
    {
        base.OnInitialized(e);
        IsEnabled = AndEnabled1 && AndEnabled2;
    }
    protected static void OnAndEnabledPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        AndEnabledTextBox textBox = (AndEnabledTextBox)obj;
        textBox.IsEnabled = textBox.AndEnabled1 && textBox.AndEnabled2;
    }
}

XMAL is more simplified when you use inherited controls.

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApp1">
    <StackPanel>
        <ToggleButton x:Name="switch1" Content="{Binding ElementName=switch1, Path=IsChecked}"/>
        <ToggleButton x:Name="switch2" Content="{Binding ElementName=switch2, Path=IsChecked}"/>
        <local:AndEnabledTextBox Text="TEXT"
                                 AndEnabled1="{Binding ElementName=switch1, Path=IsChecked, Mode=OneWay}"
                                 AndEnabled2="{Binding ElementName=switch2, Path=IsChecked, Mode=OneWay}"/>
    </StackPanel>
</Window>
Related