RelayCommand更改可以自动执行

时间:2018-06-19 12:02:38

标签: c# wpf mvvm relaycommand

对我来说,学习MVVM的当前步骤是RelayCommand。

所以我想到了这个RelayCommand类:

中继命令类

public class RelayCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Func<object, bool> _canExecute;

    public RelayCommand(Action<object> execute) : this(execute, null)
    {

    }
    public RelayCommand(Action<object> execute, Func<object, bool> canExecute)
    {
        _execute = execute ?? throw new ArgumentNullException(nameof(execute));
        _canExecute = canExecute ?? (x => true);
    }



    public bool CanExecute(object parameter)
    {
        return _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

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

    public void Refresh()
    {
        CommandManager.InvalidateRequerySuggested();
    }
}

查看隐藏代码

要测试CanExecute是对还是假,我创建了一个Click事件,如果CanExecute == true则调用Command或在CanExecute == false时显示错误消息。

if (sender is Button button)
{
    if (_viewModel.MyCommand.CanExecute(button.Tag)) // Also testet to set this parameter `null`
        _viewModel.MyCommand.Execute(button.Tag);
    else
        ErrorMessage.Error("CanExecute = false");
}

ViewModel

在ViewModel中,我创建了Command,并添加了Thread.Sleep(),以便canExecute有时间向我展示来自Code-Behind的ErrorMessage。

public ICommand MyCommand { get; set; }
public ViewModel()
{
    MyCommand = new RelayCommand(MyCommandMethod);
}

public async void MyCommandMethod(object obj)
{
    await Task.Run(() =>
    {
        Thread.Sleep(5000);
        ErrorMessage.Error(obj as string);
    });

}

现在的问题是,例如,如果我单击按钮5次,则MyCommandMetod()被使用5次。因此CanExecute将永远不会改变。

但是为什么它没有变化?

我这样理解RelayCommand:

  • 第一个-单击按钮
  • 2nd-canExecute = false(等待过程完成)
  • 第三-canExecute = true
  • 第4个-可以再次执行按钮。

例如,如果有人使用SpeedClicker并每秒点击1.000.000次,那么您就不会发送垃圾邮件。Button会单击该应用程序并使之崩溃。

1 个答案:

答案 0 :(得分:1)

创建命令时,必须将一些can-execute-logic传递给命令:

public ViewModel()
{
    MyCommand = new RelayCommand(MyCommandMethod, MyCanExecutePredicate);
}

private bool MyCanExecutePredicate( object commandParameter )
{
    // TODO: decide whether or not MyCommandMethod is allowed to execute right now
}

示例:如果您一次只允许执行一个命令,则可以按照以下思路提出一些建议:

public async void MyCommandMethod(object obj)
{
    _myCanExecute = false;
    MyCommand.Refresh();
    await Task.Run(() =>
    {
        Thread.Sleep(5000);
        ErrorMessage.Error(obj as string);
    });
    _myCanExecute = true;
    MyCommand.Refresh();
}

private bool MyCanExecutePredicate( object commandParameter )
{
    return _myCanExecute;
}