0

In WPF, I have two menu items that are mutually opposite (X ticked, then Y unticked and vice versa).

Is it possible to use single bool property to bind these two?

For example below, I have used !IsX and it is not working!

<MenuItem Header="X or Y">
    <MenuItem IsCheckable="True" Header="Is X?" IsChecked="{Binding Path=IsX, Mode=TwoWay}" />
    <MenuItem IsCheckable="True" Header="Is Y?" IsChecked="{Binding Path=!IsX, Mode=TwoWay}" />
</MenuItem>
  • _"two menu items that are mutually opposite"_ generally should be just one menu item, with a clear name. Two options that shouldn't be combined into one are generally treated as a radio group, and normal radio group techniques should be used. You may find the code semantics work better if you define an enum with values `X` and `Y` instead of using mutually opposite Boolean values, and this will make the relationship to a radio group more obvious. – Peter Duniho Apr 10 '17 at 05:34
  • I exactly did with one menu, but requirement is from project group and that I have to comply. If it is so complex, I will go with two different property to do. – OrionSoftTechnologiesSydney Apr 10 '17 at 05:39

1 Answers1

2

You need to write a custom converter for that:

[ValueConversion(typeof(bool), typeof(bool))]
public class InverseBooleanConverter: IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        if (targetType != typeof(bool))
            throw new InvalidOperationException("The target must be a boolean");

        return !(bool)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        if (targetType != typeof(bool))
            throw new InvalidOperationException("The target must be a boolean");

        return !(bool)value;
    }

    #endregion
}

And then in your markup:

<MenuItem Header="X or Y">
    <MenuItem IsCheckable="True" Header="Is X?" IsChecked="{Binding Path=IsX, Mode=TwoWay}" />
    <MenuItem IsCheckable="True" Header="Is Y?" IsChecked="{Binding Path=IsX, Mode=TwoWay, Converter={StaticResource InverseBooleanConverter}}" />
</MenuItem>

Also you should create an instance of that in your resource file

Emad
  • 3,809
  • 3
  • 32
  • 44
  • Hi Emad, thanks very much. But it seems better to use two variables than converter. Correct? – OrionSoftTechnologiesSydney Apr 10 '17 at 05:28
  • 2
    Why? Converters are pretty safe and fast. And apart from the fact that it's a conventional way to do such thing, I think that your model should represent what actually has a meaning and UI should work with it. Your model shouldn't have many properties only for UI to work with. – Emad Apr 10 '17 at 05:30
  • 2
    Thanks once again. I took your approch, it is working fine. Thanks once again. – OrionSoftTechnologiesSydney Apr 10 '17 at 06:19
  • @ParkAtStreet, Emad is right. It makes absolutely no sense to add two variables. Using a converter means you can re-use it every time you have this situation (which will happen often, usually). Two variables are just plain wrong. – r41n Apr 10 '17 at 06:36