CanExecute Logic for DelegateCommand

时间:2011-09-08 15:46:07

标签: c# wpf entity-framework command prism

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

我对CanExecute DelegateCommand遇到问题。在我致电RaiseCanExecuteChanged之前它没有更新,这是否是理想的行为?

enter image description here

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

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

<Button Command="{Binding DelegateSaveCommand}"/>
<Button Command="{Binding RelaySaveCommand}"/>

ViewModel ICommands

DelegateSaveCommand = new DelegateCommand(Save, CanSaveDelegate);
RelaySaveCommand = new RelayCommand(param => Save(), param => CanSaveRelay);

CanExecute方法/谓词

public bool CanSaveDelegate()
{
    return HasChanges;
}
public bool CanSaveRelay
{
    get { return HasChanges; }
}

两者都在使用属性HasChanges。更新HasChanges后,仅CanSaveRelay次更新。这是它的意思吗?

3 个答案:

答案 0 :(得分:21)

正如已经提到过的,这是DelagateCommand的预期行为,而不是错误。 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; }
    }
}

你可以像这样使用它:

DelegateSaveCommand = new AutoCanExecuteCommandWrapper(new DelegateCommand(Save, CanSaveDelegate));

答案 1 :(得分:0)

Prism提供的DelegateCommand中存在一个错误,它不会引发CanExecute事件。我把头撞到墙上一天,直到我进入Prism框架提供的DelegateCommand课程。我没有代码,但我可以稍微发布我的决议。

另一种方法是使用其他一个RelayCommand框架。

修改
而不是重新发布代码,还有其他提出解决方案的SO问题:

肯特B.有一篇好文章:MVVM Infrastructure: DelegateCommand

答案 2 :(得分:0)

如果您想坚持使用DelegateCommand,可以使用ObservesCanExecute

DelegateSaveCommand = new DelegateCommand(Save, CanSaveDelegate).ObservesCanExecute(CanSaveDelegate);

请注意,如果您正在使用属性执行CanExecute检查,那么ObservesProperty也可用。但是随后您的媒体资源必须调用NotifyPropertyChanged。