CanExecute Logic for DelegateCommand

Fre*_*lad 13 c# wpf command entity-framework prism

更新:焦点变成MVVM而不是实际问题,所以我正在更新它.

我有一个问题CanExecuteDelegateCommand.它在我打电话之前没有更新RaiseCanExecuteChanged,这是期望的行为吗?

在此输入图像描述

我在这里上传了一个简单的示例项目来重现这个问题:http://dl.dropbox.com/u/39657172/DelegateCommandProblem.zip

问题是这个,我有两个Buttons这样的.一个是绑定Command到一个RelayCommand实现,另一个绑定到Prism的实现DelegateCommand

<Button Command="{Binding DelegateSaveCommand}"/>
<Button Command="{Binding RelaySaveCommand}"/>
Run Code Online (Sandbox Code Playgroud)

ViewModel ICommands

DelegateSaveCommand = new DelegateCommand(Save, CanSaveDelegate);
RelaySaveCommand = new RelayCommand(param => Save(), param => CanSaveRelay);
Run Code Online (Sandbox Code Playgroud)

CanExecute方法/谓词

public bool CanSaveDelegate()
{
    return HasChanges;
}
public bool CanSaveRelay
{
    get { return HasChanges; }
}
Run Code Online (Sandbox Code Playgroud)

两人都在使用该物业HasChanges.何时HasChanges更新,仅CanSaveRelay更新.这是它的意思吗?

Pav*_*kov 23

正如已经提到的那样,这是一种行为DelagateCommand,而不是一种bug. DelegateCommand不会CanExecuteChanged自动引发事件,您必须RaiseCanExecuteChanged在适当时通过调用手动引发该事件.而事件的RelayCommand继电器则CommandManager.RequerySuggested为此.每次用户单击某个位置或按下按钮时,都会引发此事件.

对于不方便或没有适当的调用位置RaiseCanExecuteChanged的情况(比如在你的场景中你必须PropertyChanged在模型上订阅事件等)我创建了以下简单的包装器,它确保CanExecute包装命令的方法是在CommandManager.RequerySuggested事件上自动执行:

public class AutoCanExecuteCommandWrapper : ICommand
{
    public ICommand WrappedCommand { get; private set; }

    public AutoCanExecuteCommandWrapper(ICommand wrappedCommand)
    {
        if (wrappedCommand == null) 
        {
            throw new ArgumentNullException("wrappedCommand");
        }

        WrappedCommand = wrappedCommand;
    }

    public void Execute(object parameter)
    {
        WrappedCommand.Execute(parameter);
    }

    public bool CanExecute(object parameter)
    {
        return WrappedCommand.CanExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

DelegateSaveCommand = new AutoCanExecuteCommandWrapper(new DelegateCommand(Save, CanSaveDelegate));
Run Code Online (Sandbox Code Playgroud)

  • 请注意,此实现取决于`CommandManager.RequerySuggested`,仅当用户单击某处或按下某个键时才会触发(如答案中所述).如果用户未在任何地方单击,则该命令将保持不活动状态,这可能会造成混淆. (3认同)