是正确运行异步方法所需的relaycommand的异步版本

hej*_*oco 14 .net c# asynchronous relaycommand async-await

我在viewmodel中定义了以下代码.我认为类型的SaveAsync Func<Task>正在转换为Action,因为RelayCommand采取的Action不是a,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;
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

编辑:经过一些实验后,似乎异步方法本身就能正常工作.是否包含在lambda中的async/await以及该方法是否定义为async Task或没有区别async void.

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

所以看起来完整功能需要一个异步版本的RelayCommand,即canExecute可以正确地做到这一点.

Ste*_*ary 19

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

它不一定是,但你应该考虑它.

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

它正在创造一个async voidlambda.这是有问题的,因为async void不能特别好地处理异常.如果你使用RelayCommand异步代码,那么你肯定会想用try/ catch像一个在你的代码.

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

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

没有标准模式(尚未); 我在MSDN文章中概述了一些不同的方法.就个人而言,我至少IAsyncCommand在我的应用程序中定义了一个我从我的VM中公开的应用程序(很难对异步进行单元测试ICommand).

但是,无法正常工作的是canExecute谓词功能,它自动启用/禁用对命令的控件绑定.

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


Yuv*_*kov 5

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

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

当前代码在异步方面究竟做了什么?

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

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

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