wis.niowy
wis.niowy

Reputation: 87

WPF Binding with converter does not work

I am trying to bind some attributes in XAML with enum type. How it should work: I have some radio buttons in a menu bar, that set my enum value. And this enum value sets isEnabled attribute in Grid. So there is a relation: radiobutton ->(EnumToBooleanConverter)-> enum object ->(EnumToIsActiveCnoverter)-> isEnabled attribute. I have written two converters to perform that binding. Code:

<Window.Resources>
    <local:EnumToBooleanConverter x:Key="actionConverter" />
    <local:EnumToIsActiveConverter x:Key="activityConverter" />
</Window.Resources>

...

<MenuItem Header="Settings">
            <MenuItem Header="Action">
                <MenuItem Header="Draw">
                    <MenuItem.Icon>
                        <RadioButton GroupName="MenuActionButton"
                                     IsChecked="{Binding Path=appMode,
                            Converter={StaticResource actionConverter},
                            ConverterParameter={x:Static local:ApplicationMode.Draw}}"/>
                    </MenuItem.Icon>
                </MenuItem>
                <MenuItem Header="Edit">
                    <MenuItem.Icon>
                        <RadioButton GroupName="MenuActionButton"
                                     IsChecked="{Binding Path=appMode,
                            Converter={StaticResource actionConverter},
                            ConverterParameter={x:Static local:ApplicationMode.Edit}}"/>
                    </MenuItem.Icon>
                </MenuItem>
                <MenuItem Header="Constraints">
                    <MenuItem.Icon>
                        <RadioButton GroupName="MenuActionButton"
                                     IsChecked="{Binding Path=appMode,
                            Converter={StaticResource actionConverter},
                            ConverterParameter={x:Static local:ApplicationMode.Constraints}}"/>
                    </MenuItem.Icon>
                </MenuItem>
            </MenuItem>
        </MenuItem>

CS file:

public partial class MainWindow : Window
{
    public ApplicationMode appMode { get; set; }

    public MainWindow()
    {
        this.appMode = ApplicationMode.Draw;
        InitializeComponent();
    }
}

public class EnumToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        //return value.Equals(parameter);
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value.Equals(true) ? parameter : Binding.DoNothing;
    }
}
public class EnumToIsActiveConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value.Equals(parameter);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        //return value.Equals(true) ? parameter : Binding.DoNothing;
        return Binding.DoNothing;
    }
}
public enum ApplicationMode
{
    Draw,
    Edit,
    Constraints
}

EnumToBooleanConverter changes enum value to a given parameter when radiobutton is checked and EnumToIsActiveConverter changes isEnabled attribute of a given element when enum value is set to a given parameter. It seems to me it should be working just fine. What am I missing in here?

Upvotes: 0

Views: 1845

Answers (2)

dovid
dovid

Reputation: 6491

More simple solution, without RadioButton:

a. use the MenuItem Checkable feature for the icon job, and bind the IsChecked to appMode property:

<MenuItem Header="Action">
    <MenuItem Header="Draw" IsCheckable="True"
          IsChecked="{Binding Path=appMode,
                              Converter={StaticResource actionConverter},
                              ConverterParameter={x:Static local:ApplicationMode.Draw}}" />

    <MenuItem Header="Edit" IsCheckable="True"
          IsChecked="{Binding Path=appMode,
                              Converter={StaticResource actionConverter},
                              ConverterParameter={x:Static local:ApplicationMode.Edit}}" />
</MenuItem>

b. in the code, change the property to trigger the PropertyChange event:

public partial class MainWindow : Window, INotifyPropertyChanged
{

    private ApplicationMode _appMode;

    public ApplicationMode appMode
    {
        get { return _appMode; }
        set
        {
            _appMode = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(appMode)));
        }
    }

    public MainWindow()
    {
        this.appMode = ApplicationMode.Draw;
        InitializeComponent();
    }

    public event PropertyChangedEventHandler PropertyChanged;

}

c. in the converter fix the ConvertBack metode:

public class EnumToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value.Equals(parameter);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return parameter;
    }
}

Upvotes: 1

dovid
dovid

Reputation: 6491

You are using a RadioButton control, But only as an indicator.

So clicking on the item does not change the property value because only the MenuItem receive the Click, not the RadioButton.

also it's a bit of a waste, because for V (current active indication) you do not need a RadioButton control, quite a Path with visibility binding.

I will present you with a solution in the existing way:

a. add Click event to each MenuItem

b. put the relevant Value in Tag property (This is for the simplicity of the event as you will see)

c. add to your MainWindow class implement of INotifyPropertyChanged interface to alow XAML know the appMode modofication.

here the code, XAML:

<MenuItem Header="Draw" Click="MenuItem_Click" Tag="{x:Static local:ApplicationMode.Draw}" >
    <MenuItem.Icon>
        <RadioButton GroupName="MenuActionButton"
                IsChecked="{Binding Path=appMode,
    Converter={StaticResource actionConverter},
    ConverterParameter={x:Static local:ApplicationMode.Draw}}"/>
    </MenuItem.Icon>
</MenuItem>
<MenuItem Header="Edit" Click="MenuItem_Click" Tag="{x:Static local:ApplicationMode.Edit}">
    <MenuItem.Icon>
        <RadioButton GroupName="MenuActionButton"
                IsChecked="{Binding Path=appMode,
    Converter={StaticResource actionConverter},
    ConverterParameter={x:Static local:ApplicationMode.Edit}}"/>
    </MenuItem.Icon>
</MenuItem>

the MenuItem_Click for Click event:

public event PropertyChangedEventHandler PropertyChanged;

private void MenuItem_Click(object sender, RoutedEventArgs e)
{
    var item = (MenuItem)sender;
    appMode = (ApplicationMode) item.Tag;
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(appMode)));
}

Upvotes: 1

Related Questions