【问题标题】:is asynchronous version of relaycommand required in order to run async methods correctly为了正确运行异步方法,需要异步版本的 relaycommand
【发布时间】:2014-08-02 20:52:50
【问题描述】:

我在视图模型中定义了以下代码。我认为 Func<Task> 类型的 SaveAsync 正在转换为 Action ,因为 RelayCommand 采用的是 Action 而不是 Func<Task> 但我不清楚它的含义。

1) RelayCommand 是否需要替换为异步版本(RelayCommandAsync)? 2)当前代码在异步方面到底做了什么? 3) 如果有什么可以/应该改变以改进/纠正它怎么办?

private ICommand _saveCommand;
public ICommand SaveCommand
{
    get { return _saveCommand ?? (_saveCommand = new RelayCommand(async () => await SaveAsync(), CanSave)); }
}

public bool CanSave()
{
    return !IsBusy;
}

private async Task SaveAsync()
{
    IsBusy = true;

    try
    {
        await _service.SaveAsync(SomeProperty); 
    }
    catch ( ServiceException ex )
    {
        Message = "Oops. " + ex.ToString();
    }
    finally
    {
        IsBusy = false;
    }
}

谢谢!

编辑:经过一些试验,异步方法本身似乎可以正常工作。并且无论 async/await 是否包含在 lambda 中,或者该方法是否定义为 async Taskasync void,都没有区别。

但是,不能正常工作的是canExecute 谓词功能,它会自动启用/禁用与命令的控件绑定。发生的情况是该按钮在异步方法运行时被正确禁用,但之后未启用。我必须单击一次窗口上的某个位置,然后再次启用它。

因此,完整功能似乎需要 RelayCommand 的异步版本,即canExecute 可以正确执行它的操作。

【问题讨论】:

  • IsBusy 是否实现 iNotifyPropertyChanged err 你的 vm 会做吗?属性是否会调用你的方法来调用事件?还是dp?在这种情况下,您必须在 UI 线程上更改它。只是处理这个是一个典型的错误。

标签: c# .net asynchronous async-await relaycommand


【解决方案1】:

1) RelayCommand 是否需要替换为异步版本(RelayCommandAsync)?

不一定是这样,但你应该考虑一下。

2) 当前代码在异步方面到底做了什么?

它正在创建一个async void lambda。这是有问题的,因为async void 不能很好地处理异常。如果您确实将RelayCommand 与异步代码一起使用,那么您肯定会希望使用try/catch,就像您的代码中的那样。

3) 如果我可以/应该改变什么来改进/纠正它,该怎么办?

如果这是您代码中唯一的异步命令,我会说没问题。但是,如果您发现您的应用程序中有多个具有相似语义的异步命令,那么您应该考虑编写RelayCommandAsync

目前还没有标准模式;我在MSDN article 中概述了几种不同的方法。就个人而言,至少我在我的应用程序中定义了一个IAsyncCommand,我从我的虚拟机中公开了它(很难对异步ICommand 进行单元测试)。

但是,无法正常工作的是 canExecute 谓词功能,该功能会自动启用/禁用与命令的控件绑定。

假设RelayCommand.CanExecuteChanged 委托给CommandManager,那么你可以在设置IsBusy 后调用CommandManager.InvalidateRequerySuggested

【讨论】:

    【解决方案2】:

    RelayCommand 是否需要替换为异步版本 (RelayCommandAsync)?

    不,RelayCommand 将在此处按需要工作。

    当前代码在异步方面到底做了什么?

    发生的情况是,当重载决议在编译时启动时,它会选择采用 Action 的重载,这意味着您的方法被转换为 async void,这就是您的代码编译的原因。

    3) 如果我可以/应该改变什么来改进/纠正它,该怎么办?

    有异步委托命令的实现。你可以找到一个here。需要注意的一件重要事情是异常处理。如果在绑定到 WPF 控件的异步 ICommand 中出现未处理的异常,该异常将传播到活页夹,并且未处理且未被注意。

    【讨论】:

      【解决方案3】:

      我认为您不需要中继命令的异步版本。您的实现看起来不错。它有效吗?

      如果您想测试主体是否正在异步运行,请添加 await task.delay(20000) 并查看 UI 在命令运行时是否保持响应。

      【讨论】:

        【解决方案4】:

        没有。在绑定上设置 IsAsync。像这样:

        <Button Command="{Binding DoCommand, IsAsync=True}" />
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-12-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多