首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >取消AsyncRelayCommand

取消AsyncRelayCommand
EN

Stack Overflow用户
提问于 2022-11-07 13:13:51
回答 1查看 71关注 0票数 0

这是WPF (.NET Framework4.8)。我需要在UI中提供两个<Button>来启动和停止一个长期运行的后台进程。最初应该启用“开始”按钮,并在发出命令后将其禁用(以避免再次单击)。“停止”按钮最初将被禁用,并将在进程开始运行时启用。

我使用的是AsyncRelayCommandWindows社区工具包的MVVM库中提供的。这些按钮通过普通的XAML绑定绑定到它们的VM。底层命令如下所示:

代码语言:javascript
运行
复制
private AsyncRelayCommand _StartPumpingCommand;
public AsyncRelayCommand StartPumpingCommand
{
  get
  {
    _StartPumpingCommand ??= new AsyncRelayCommand(async (CancellationToken token) =>
      {
        dispatcher.Invoke(() => _CancelPumpingCommand.NotifyCanExecuteChanged());
        await SomeTask(token);
      },
      () => {
        /* SomeTask is not running and a cancellation has not been requested  */
        return !_StartPumpingCommand.IsRunning && !_StartPumpingCommand.IsCancellationRequested;
      });

    return _StartPumpingCommand;
  }
}


private RelayCommand _CancelPumpingCommand;
public RelayCommand CancelPumpingCommand
{
  get
  {
    _CancelPumpingCommand ??= new RelayCommand(() =>
      {
        if(_StartPumpingCommand?.IsRunning??false)
          _StartPumpingCommand.Cancel();
      },
      () => _StartPumpingCommand?.IsRunning??false);

    return _CancelPumpingCommand;
  }
}

问题:

  1. 这两个命令的实现正确吗?
  2. AsyncRelayCommand内部是否包含CancellationTokenSource魔术,还是需要自己在VM类中创建一个,并在上面的两个命令中使用它?
  3. 如何将StartPumpingCommand的完成与CancelPumpingCommand通信,从而相应地启用/禁用UI中的按钮?我们应该在CancelPumpingCommand.NotifyCanExecuteChanged()返回后打电话给SomeTask()吗?既然CancelPumpingCommand使用StartPumpingCommand.IsRunning属性来决定其可用性,那么它将如何运行,并且StartPumpingCommand仍在运行,对吗?
EN

Stack Overflow用户

发布于 2022-11-07 14:34:09

弄明白了。以下是在Community中执行异步命令的正确方法,以防它帮助某人:

代码语言:javascript
运行
复制
private AsyncRelayCommand _StartPumpingCommand;
public AsyncRelayCommand StartPumpingCommand
{
  get
  {
    _StartPumpingCommand ??= new AsyncRelayCommand(async (CancellationToken token) =>
      {
        try
        {
          await Task.Run(() => SomeTask(token), token);
        }
        catch(OperationCanceledException)
        {
          //do whatever u want to do in case of task cancellation
        }
      },
      () => !_StartPumpingCommand.IsRunning);

    return _StartPumpingCommand;
  }
}

private ICommand _CancelPumpingCommand;
public ICommand CancelPumpingCommand
{
  get
  {
    _CancelPumpingCommand ??= StartPumpingCommand.CreateCancelCommand();
    return _CancelPumpingCommand;
  }
}

private async Task SomeTask(CancellationToken token)
{
  //I'm using "await foreach" which requires C# 8 and an Nuget
  //package named `Microsoft.Bcl.AsyncInterfaces` when targeting
  //.NET Framework. You may use some other way of creating a 
  //Task here.
  await foreach(...)
  { 
    token.ThrowIfCancellationRequested();

    //do stuff
  }
}

这完全正确。我的UI是完全响应的(没有死锁),我可以取消和重新启动任务的任何次数。这表明AsyncRelayCommand内部包含任务取消魔术,只需要一个可使用的方法即可工作。

票数 0
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74347185

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档