WPF - How to force a Command to re-evaluate 'CanExecute' via its CommandBindings

前端 未结 6 1239
礼貌的吻别
礼貌的吻别 2020-11-29 17:47

I have a Menu where each MenuItem in the hierarchy has its Command property set to a RoutedCommand I\'ve defined. The as

相关标签:
6条回答
  • 2020-11-29 17:51

    This is what worked for me: Put the CanExecute before the Command in the XAML.

    0 讨论(0)
  • 2020-11-29 17:56

    I couldnt use CommandManager.InvalidateRequerySuggested(); because I was getting performance hit.

    I have used MVVM Helper's Delegating command, which looks like below (i have tweaked it a bit for our req). you have to call command.RaiseCanExecuteChanged() from VM

    public event EventHandler CanExecuteChanged
    {
        add
        {
            _internalCanExecuteChanged += value;
            CommandManager.RequerySuggested += value;
        }
        remove
        {
            _internalCanExecuteChanged -= value;
            CommandManager.RequerySuggested -= value;
        }
    }
    
    /// <summary>
    /// This method can be used to raise the CanExecuteChanged handler.
    /// This will force WPF to re-query the status of this command directly.
    /// </summary>
    public void RaiseCanExecuteChanged()
    {
        if (canExecute != null)
            OnCanExecuteChanged();
    }
    
    /// <summary>
    /// This method is used to walk the delegate chain and well WPF that
    /// our command execution status has changed.
    /// </summary>
    protected virtual void OnCanExecuteChanged()
    {
        EventHandler eCanExecuteChanged = _internalCanExecuteChanged;
        if (eCanExecuteChanged != null)
            eCanExecuteChanged(this, EventArgs.Empty);
    }
    
    0 讨论(0)
  • 2020-11-29 18:04

    Not the prettiest in the book, but you can use the CommandManager to invalidate all commandbinding:

    CommandManager.InvalidateRequerySuggested();
    

    See more info on MSDN

    0 讨论(0)
  • 2020-11-29 18:05

    If you have rolled your own class that implements ICommand you can lose a lot of the automatic status updates forcing you to rely on manual refreshing more than should be needed. It can also break InvalidateRequerySuggested(). The problem is that a simple ICommand implementation fails to link the new command to the CommandManager.

    The solution is to use the following:

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
    
        public void RaiseCanExecuteChanged()
        {
            CommandManager.InvalidateRequerySuggested();
        }
    

    This way subscribers attach to CommandManager rather than your class and can properly participate in command status changes.

    0 讨论(0)
  • 2020-11-29 18:08

    I've implemented a solution to handle property dependency on commands, here the link https://stackoverflow.com/a/30394333/1716620

    thanks to that you'll end up having a command like this:

    this.SaveCommand = new MyDelegateCommand<MyViewModel>(this,
        //execute
        () => {
          Console.Write("EXECUTED");
        },
        //can execute
        () => {
          Console.Write("Checking Validity");
           return PropertyX!=null && PropertyY!=null && PropertyY.Length < 5;
        },
        //properties to watch
        (p) => new { p.PropertyX, p.PropertyY }
     );
    
    0 讨论(0)
  • 2020-11-29 18:13

    For anyone who comes across this later; If you happen to be using MVVM and Prism, then Prism's DelegateCommand implementation of ICommand provides a .RaiseCanExecuteChanged() method to do this.

    0 讨论(0)
提交回复
热议问题