Вопрос

I know I can force reevalution of CanExecute in the view model, however, this requires the view model to register to all related data change events, which might not be always feasible.

Since the commands are only used in the context menu, and during the context menu is open, the data that affect CanExecute cannot be changed, it would be sufficient if CanExecute is reevaluated only when context menu is being opened.

To do this, I can hook up context menu open event and call view model to call RaiseCanExecuteChanged on each ICommand the context menu uses, but it's tedious and anti MVVM. I am wondering if there is an easier way to achieve this?

Это было полезно?

Решение

Yes there is. Use this implementation of ICommand. It reevaluates on each interaction, in your case "Context menu opening". It is not so performance efficient, but if you are not having hundreds of commands then should do the work:

public class Command<TArgs> : ICommand
{
    public Command(Action<TArgs> exDelegate)
    {
        _exDelegate = exDelegate;
    }

    public Command(Action<TArgs> exDelegate, Func<TArgs, bool> canDelegate)
    {
        _exDelegate = exDelegate;
        _canDelegate = canDelegate;
    }

    protected Action<TArgs> _exDelegate;
    protected Func<TArgs, bool> _canDelegate;

    #region ICommand Members

    public bool CanExecute(TArgs parameter)
    {
        if (_canDelegate == null)
            return true;

        return _canDelegate(parameter);
    }

    public void Execute(TArgs parameter)
    {
        if (_exDelegate != null)
        {
            _exDelegate(parameter);
        }
    }

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

    bool ICommand.CanExecute(object parameter)
    {
        if (parameter != null)
        {
            var parameterType = parameter.GetType();
            if (parameterType.FullName.Equals("MS.Internal.NamedObject"))
                return false;
        }

        return CanExecute((TArgs)parameter);
    }

    void ICommand.Execute(object parameter)
    {
        Execute((TArgs)parameter);
    }

    #endregion
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top