在MVVM中async/await没有Void方法

本文关键字:没有 Void 方法 await MVVM async | 更新日期: 2023-09-27 18:16:16

我想在我的windows phone 8 MVVM项目上使用async/await,我正在努力寻找一个很好的方法来使用这个api实现我的iccommands。我一直在阅读一些关于这个主题的文章,我在下面的MSDN上遇到了这篇文章,它说我必须避免async void,因为它很难捕捉未处理的异常:http://msdn.microsoft.com/en-us/magazine/jj991977.aspx在我问的另一个关于这个主题的问题中,有人也说我不应该使用异步空。除非有事件。

但问题是,我能在互联网上找到的所有例子都使用异步空洞。我找到的这两篇文章就是例子:http://richnewman.wordpress.com/2012/12/03/tutorial-asynchronous-programming-async-and-await-for-beginners/和http://blog.mycupof.net/2012/08/23/mvvm-asyncdelegatecommand-what-asyncawait-can-do-for-uidevelopment/

最后一个是使用async/await的iccommand实现,但它也使用async void。我正试图想出一个解决方案,所以我写了这个基于RelayCommand的iccommand实现:

public delegate Task AsyncAction();
public class RelayCommandAsync : ICommand
{
    private AsyncAction _handler;
    public RelayCommandAsync(AsyncAction handler)
    {
        _handler = handler;
    }
    private bool _isEnabled;
    public bool IsEnabled
    {
        get { return _isEnabled; }
        set
        {
            if (value != _isEnabled)
            {
                _isEnabled = value;
                if (CanExecuteChanged != null)
                {
                    CanExecuteChanged(this, EventArgs.Empty);
                }
            }
        }
    }
    public bool CanExecute(object parameter)
    {
        return IsEnabled;
    }
    public event EventHandler CanExecuteChanged;
    public void Execute(object parameter)
    {
        ExecuteAsync();
    }
    private Task ExecuteAsync()
    {
        return _handler();
    }
}

我试着这样使用它:在构造函数中:

saveCommand = new RelayCommandAsync(SaveSourceAsync);

:

private async Task SaveSourceAsync()
{
    await Task.Run(() => { Save(); });
}
private void Save()
{
    // Slow operation
}

问题是我对这个和其他任何实现都感到不舒服,因为我不知道哪个是最好的和最优的。

谁能给一些光我应该如何使用它,最好与MVVM?

在MVVM中async/await没有Void方法

在引用的文章中,我确实指出ICommand.Execute实际上是一个事件处理程序,因此它将被视为"避免async void"指南的异常:

总结第一条原则,你应该选择async Task而不是async void…该准则的例外是异步事件处理程序,它必须返回void。此异常包括逻辑上是事件处理程序的方法,即使它们不是字面上的事件处理程序(例如,iccommand。执行实现)。

关于您的ICommand实现,它实际上通过而不是使用async void引入了一个缺陷:ICommand.Execute实现将丢弃Task而不观察其异常。因此,实现将忽略async委托引发的任何异常。

相反,您链接到的博客文章有一个async void ICommand.Execute, awaitTask,允许异常传播到UI同步上下文。在这种情况下,这是期望的行为,因为它与同步ICommand.Execute引发异常时得到的行为相同。

如果你有兴趣,我想让你尝试一下我写的ICommand或两个,以便将来可能包含在我的AsyncEx库中。第一个是一个简单的命令,与您在博客中发布的命令非常相似。第二个是更完整的"异步命令"实现,包括取消、进度报告和CanExecute的自动管理。