异步 ICommand 实现

Async ICommand implementation

当我尝试在默认情况下执行时禁用命令时(即使没有向它传递 CanExecute 谓词),我的 asny ICommand 实现遇到了一个奇怪的行为。

public bool CanExecute(object parameter)
{
  if (CanExecutePredicate == null)
  {
    return !mIsExecuting;
  }

  return !mIsExecuting && CanExecutePredicate(parameter);
}

public async void Execute(object parameter)
{
  mIsExecuting = true;
  await ExecuteAsync(parameter);
  mIsExecuting = false;
}

我尝试引入一个私有布尔值,我在执行之前将其设置为 true,之后设置为 false。执行完成后设置 bool,但仅在单击鼠标按钮或移动鼠标或 w/e.

后才调用 CanExecute

现在我试着打电话

CanExecute(null);

之后
mIsExecuting = false;

但这也无济于事。我不知道我错过了什么。

感谢您的帮助

编辑:

为了澄清,我还为此 class 添加了构造函数:

 public AsyncRelayCommand(Func<object, Task> execute)
  : this(execute, null)
{
}

public AsyncRelayCommand(Func<object, Task> asyncExecute,
               Predicate<object> canExecutePredicate)
{
  AsyncExecute = asyncExecute;
  CanExecutePredicate = canExecutePredicate;
}

protected virtual async Task ExecuteAsync(object parameter)
{
  await AsyncExecute(parameter);
}

在异步场景中,WPF 往往不知道何时检查 CanExecute,这就是为什么你在 Icommand 接口中有 "CanExecuteChanged" 事件。

你的命令实现中应该有这样的东西:

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

    remove { CommandManager.RequerySuggested -= value; }
}

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

使用上面的代码,您现在可以执行此操作:

public async void Execute(object parameter)
{
    mIsExecuting = true;

    RaiseCanExecuteChanged ( ); // Not necessary if Execute is not called locally

    await ExecuteAsync(parameter);
    mIsExecuting = false;

    RaiseCanExecuteChanged ( );
}

这将告诉 WPF 您想要刷新命令的 CanExecute 状态。