简体   繁体   English

没有Void方法的MVVM中的async / await

[英]async/await in MVVM without Void methods

I want to use async/await on my windows phone 8 MVVM project and I'm struggling to find a good way to implement my ICommands using this api. 我想在我的Windows Phone 8 MVVM项目上使用async / await,我正在努力找到一种使用这个api实现我的ICommands的好方法。 I've been reading a few articles about the subject and I bumped into this one from MSDN below, which states that I have to avoid async voids since it gets difficult to catch unhandled exceptions: http://msdn.microsoft.com/en-us/magazine/jj991977.aspx In another question I asked about the subject, someone also said that I shouldn't use async voids. 我一直在阅读一些关于这个主题的文章,我在下面的MSDN中提到了这个问题,其中指出我必须避免异步空洞,因为它很难捕获未处理的异常: http//msdn.microsoft.com/en -us / magazine / jj991977.aspx在另一个问我有关这个问题的问题,有人还说我不应该使用异步空洞。 Unless with events. 除非有事件。

But the problem is that all examples I can find on the internet use async voids. 但问题是我可以在互联网上找到的所有例子都使用异步空洞。 This two articles I found are examples: http://richnewman.wordpress.com/2012/12/03/tutorial-asynchronous-programming-async-and-await-for-beginners/ and http://blog.mycupof.net/2012/08/23/mvvm-asyncdelegatecommand-what-asyncawait-can-do-for-uidevelopment/ 我找到的这两篇文章是例子: http//richnewman.wordpress.com/2012/12/03/tutorial-asynchronous-programming-async-and-await-for-beginners/http://blog.mycupof.net / 2012/08/23 / MVVM-asyncdelegatecommand乜asyncawait灿做换uidevelopment /

The last one is an implementation of ICommand using async/await, but it also uses async voids. 最后一个是使用async / await的ICommand实现,但它也使用异步空洞。 I'm trying to come up with a solution for this, so I wrote this implementation of ICommand based on the RelayCommand: 我正在尝试为此提出解决方案,因此我基于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();
    }
}

And I'm trying to use it like this: in the constructor: 我试图像这样使用它:在构造函数中:

saveCommand = new RelayCommandAsync(SaveSourceAsync);

then: 然后:

private async Task SaveSourceAsync()
{
    await Task.Run(() => { Save(); });
}

private void Save()
{
    // Slow operation
}

The problem is that I'm not feeling comfortable with this and any other implementation as I don't know which is the best and optimal. 问题是我对这个和任何其他实现感到不舒服,因为我不知道哪个是最好和最优的。

Can anyone give some light on how I should use it, preferably with MVVM? 任何人都可以说明我应该如何使用它,最好是使用MVVM?

In the referenced article, I did point out that ICommand.Execute is practically an event handler, so it would be considered an exception from the "avoid async void " guideline: 在引用的文章中,我确实指出ICommand.Execute实际上是一个事件处理程序,因此它将被视为“避免async void ”指南的异常:

To summarize this first guideline, you should prefer async Task to async void... The exception to this guideline is asynchronous event handlers, which must return void. 总结第一个指南,你应该更喜欢async Task to async void ...本指南的例外是异步事件处理程序,它必须返回void。 This exception includes methods that are logically event handlers even if they're not literally event handlers (for example, ICommand.Execute implementations). 此异常包括逻辑事件处理程序的方法,即使它们不是字面上的事件处理程序(例如,ICommand.Execute实现)。

Regarding your ICommand implementation, it actually introduces a flaw by not using async void : the ICommand.Execute implementation will discard the Task without observing its exceptions. 关于你的ICommand实现,它实际上通过使用async void引入了一个缺陷: ICommand.Execute实现将丢弃Task而不观察它的异常。 So that implementation will ignore any exceptions raised by the async delegate. 因此,该实现将忽略async委托引发的任何异常。

In contrast, the blog post you linked to has an async void ICommand.Execute which await s the Task , allowing the exception to propagate to the UI synchronization context. 相反,您链接到的博客文章有一个async void ICommand.Execute await Task ,允许异常传播到UI同步上下文。 Which - in this case - is the desired behavior because it's the same behavior you get when a synchronous ICommand.Execute raises an exception. 其中 - 在这种情况下 - 是所需的行为,因为它与同步ICommand.Execute引发异常时获得的行为相同。

If you have the inclination, I'd like you to try out an ICommand or two that I've written for possible future inclusion in my AsyncEx library . 如果您有这种倾向,我希望您尝试使用我编写的一两个ICommand ,以便将来可能包含在我的AsyncEx库中 The first one is a simple command very similar to the one in the blog you posted. 第一个是一个简单的命令,非常类似于您发布的博客中的命令。 The second one is a much more complete "asynchronous command" implementation including cancellation, progress reporting, and automatic management of CanExecute . 第二个是更完整的“异步命令”实现,包括取消,进度报告和CanExecute自动管理。 I'd appreciate any feedback. 我很感激任何反馈。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM