7

我想在我的 windows phone 8 MVVM 项目上使用 async/await,我正在努力寻找一种使用这个 api 实现我的 ICommands 的好方法。我一直在阅读有关该主题的几篇文章,我从下面的 MSDN 中偶然发现了这篇文章,其中指出我必须避免异步空洞,因为很难捕获未处理的异常: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 的 ICommand 实现,但它也使用 async voids。我试图为此想出一个解决方案,所以我基于 RelayCommand 编写了这个 ICommand 实现:

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 吗?

4

1 回答 1

22

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

总结第一个准则,您应该更喜欢 async Task 而不是 async void ...该准则的例外是异步事件处理程序,它必须返回 void。此异常包括逻辑上是事件处理程序的方法,即使它们不是字面上的事件处理程序(例如,ICommand.Execute 实现)。

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

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

如果您愿意,我希望您尝试一ICommand两个我为将来可能包含在我的AsyncEx 库中而编写的内容。第一个是一个简单的命令,与您发布的博客中的命令非常相似。第二是更完整的“异步命令”实现,包括取消、进度报告和CanExecute. 我会很感激任何反馈。

于 2013-05-31T02:48:29.670 回答