Home > Net >  WPF disable menu element using using CheckBox and Command
WPF disable menu element using using CheckBox and Command

Time:10-25

I have two menu items, "message", and "check". "Check" is Checkable and have a checkbox near the header. I want, by clicking on Check to uncheck it, and disable the "message" item. Also, I want to do it by both clicking, and using a shortcut. I wrote some additional classes like RelayCommand

public class RelayCommand : ICommand
{
    private Action<object> _execute;
    private Func<object, bool> _canExecute;

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested  = value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        _canExecute = canExecute;
        _execute = execute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}

Observable object (which is analogue of INotifyOnPropertyChanged)

public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string name = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}

and MainViewModel class

public class MainViewModel : ObservableObject
    {
        private readonly MainWindow _mainWindow;
        private bool _isChecked { get; set; } = true;

        public bool IsChecked
        {
            get
            {
                return _isChecked;
            }
            set
            {
                _isChecked = value;
                OnPropertyChanged();
            }
        }
   
        public RelayCommand Check { get; set; }
        public MainViewModel(MainWindow mainwindow)
        {
            _mainWindow = mainwindow;

            IsChecked = false;
            Check = new RelayCommand(o =>
            {
                if (IsChecked == false)
                {
                    _mainWindow.Message_menu_item.IsEnabled = true;
                    IsChecked = true;
                }
                else
                {
                    _mainWindow.Message_menu_item.IsEnabled = false;
                    IsChecked = false;
                }
            });
        }
}

My xaml

<MenuItem Header="File">
            <MenuItem 
                      Name="Message_menu_item"
                      InputGestureText="Ctrl M"
                      Header="_Message"/>
            <MenuItem
                      Name="Check_menu_item"
                      InputGestureText="Ctrl C"
                      Command="{Binding Check}"
                      Header="Check"
                      IsCheckable="True"
                      IsChecked="{Binding IsChecked}"/>
            <Separator />
            <MenuItem Header="Exit"
                      InputGestureText="Ctrl E"/>
            
        </MenuItem>

And binding

<KeyBinding Key="C" Modifiers="Ctrl" Command="{Binding Check}"/>

I wanted to start an app with checked checkbox and available Message menu item, but it is starting unchecked, and by clicking it, it simply disabling the message, and ignoring the checkbox (it only work ones, clicking on it again doesn't change anything). It only works fine using the shortcut, BUT I can only use shortcut after clicking the menu dropdown button "file" in my case (like this, and if it is closed shortcut doesn't work menu dropdown) I don't understand why is it working so weird, please help.

CodePudding user response:

I wanted to start an app with checked checkbox

If so, you should change the initialization IsChecked = false; in your viewmodel constructor accordingly.

The weird behaviour of the checkbox is a result of modifying IsChecked from the Check command plus binding it to the IsChecked property of the menu item without specifying a mode (which results in a two way binding). So, when using the menu, the property is toggled twice: via command and via the binding. Using the key binding works, because it only triggers the command.

To solve this, either change the binding mode to OneWay or don't change the property value in the command.

Furthermore: You should remove the reference to the window from your viewmodel. This can be achieved by binding the IsEnabled property of the message menu item to another property on your viewmodel like this:

public bool IsMessageMenuEnabled => !this.IsChecked;

public bool IsChecked
{
    get => this.isChecked;
    set
    {
        this.isChecked = value;
        this.OnPropertyChanged();
        this.OnPropertyChanged(nameof(this.IsMessageMenuEnabled));
    }
}
  • Related