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

.NetWpfCommandCommandbinding

.Net Problem Overview


I have a Menu where each MenuItem in the hierarchy has its Command property set to a RoutedCommand I've defined. The associated CommandBinding provides a callback for the evaluation of CanExecute which controls the enabled state of each MenuItem.

This almost works. The menu items initially come up with the correct enabled and disabled states. However when the data that my CanExecute callback uses changes, I need the command to re-request a result from my callback in order for this new state to be reflected in the UI.

There do not appear to be any public methods on RoutedCommand or CommandBinding for this.

Note that the callback is used again when I click or type into the control (I guess it's triggered on input because mouse-over doesn't cause the refresh).

.Net Solutions


Solution 1 - .Net

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

CommandManager.InvalidateRequerySuggested();

See more info on MSDN

Solution 2 - .Net

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.

Solution 3 - .Net

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);
}

Solution 4 - .Net

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.

Solution 5 - .Net

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 }
 );

Solution 6 - .Net

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDrew NoakesView Question on Stackoverflow
Solution 1 - .NetArcturusView Answer on Stackoverflow
Solution 2 - .NetCodingWithSpikeView Answer on Stackoverflow
Solution 3 - .NetBek RaupovView Answer on Stackoverflow
Solution 4 - .NetAndrue CopeView Answer on Stackoverflow
Solution 5 - .NetNot ImportantView Answer on Stackoverflow
Solution 6 - .NetrmustakosView Answer on Stackoverflow