简体   繁体   English

异步等待MVVM XAML应用程序

[英]Async await in MVVM XAML Applications

I try to understand how should I receive initial data in my ViewModels with async/await pattern. 我试着理解如何在我的ViewModel中使用async / await模式接收初始数据。 Let's look at the code: 我们来看看代码:

public interface IPeopleService
{
     Task<IEnumerable<Person> GetPeopleAsync();
}


public MainViewModel
{
    public ObservableCollection<Person> People{get;set;}

  public MainViewModel(IPeopleService peopleService)
  {
       LoadMyData(peopleService);
  }

    public async Task LoadMyData(IPeopleService peopleService)
    {
       try
       {
          People = await peopleService.GetPeopleAsync();
       }
       catch(Exception e)
       {
         //log       
         //notify user    
       }
    }

}

There is a PeopleService which contains asynchronous method to People Data. PeopleService包含People Data的异步方法。 It is injected with IOC (whatever). 注入IOC(无论如何)。 After that I invoke asynchronous operation LoadMyData (to prevent blocking UI, so no await keyword) and inside that method I invoke asynchronous operation from service catching all exceptions and notyfying user. 之后我调用异步操作LoadMyData(以防止阻塞UI,因此没有await关键字),并且在该方法中,我从服务中调用异步操作来捕获所有异常并且不对用户进行操作。 What's wrong with this approach? 这种方法有什么问题?

I read article from msdn: https://msdn.microsoft.com/en-us/magazine/dn605875.aspx and when I noticed creating a generic class for this kind of Tasks and changing all my properties to use that class as generic parameter, change XAML Bindings to receive a Property.Result property, I think it's crazy and creates a big mess in the project. 我从msdn阅读文章: https//msdn.microsoft.com/en-us/magazine/dn605875.aspx当我注意到为这种任务创建一个泛型类并更改我的所有属性以将该类用作泛型参数,更改XAML Bindings以接收Property.Result属性,我认为这很疯狂并且在项目中造成了很大的混乱。 Furthermore properties in ViewModel specifies that this property is asynchronous which in my opinion is bad design. 此外,ViewModel中的属性指定此属性是异步的,在我看来是糟糕的设计。 What is the EASIEST way to solve my problem? 什么是最简单的方法来解决我的问题? Is my solution acceptable to keep everything simple? 我的解决方案是否可以保持简单?

After that I invoke asynchronous operation LoadMyData (to prevent blocking UI, so no await keyword) and inside that method I invoke asynchronous operation from service catching all exceptions and notyfying user. 之后我调用异步操作LoadMyData(以防止阻塞UI,因此没有await关键字),并且在该方法中,我从服务中调用异步操作来捕获所有异常并且不对用户进行操作。 What's wrong with this approach? 这种方法有什么问题?

Your UI is not blocked while loading the data. 加载数据时不会阻止您的UI。 That's good. 那很好。 But asynchronous data loading brings up some questions: What does the UI show while the data is loading? 但异步数据加载会带来一些问题:在加载数据时UI会显示什么? How does the UI show errors to the user? UI如何向用户显示错误?

In your current code, the UI list is just empty while the data is loading. 在当前代码中,UI列表在加载数据时只是空的。 IMO there should be at the very least a "loading" kind of state so the user can distinguish between an empty result set and an operation still in progress. IMO应至少具有“加载”类型的状态,因此用户可以区分空结果集和仍在进行中的操作。 Also, your notify user code I assume is bringing up a dialog box or something - via code, not via data binding. 此外,我假设您的notify user代码是通过代码而不是通过数据绑定来打开对话框或其他内容。 IMO an error indicator is better than a modal dialog. IMO错误指示器优于模态对话框。

The purpose behind NotifyTaskCompletion<T> is that it acts as a data-bindable asynchronous operation. NotifyTaskCompletion<T>背后的目的是它充当数据绑定异步操作。 So you can use its properties to change to/from the "loading" and "error" states. 因此,您可以使用其属性更改为“加载”和“错误”状态。 This is why your bindings have to change to .Result - because you're binding to the result of the asynchronous operation. 这就是为什么你的绑定必须改为.Result - 因为你绑定到异步操作的结果 If you don't want to display a "loading" indicator and you don't want to display errors via data-binding, then yes, NotifyTaskCompletion<T> would be overkill. 如果您不想显示“加载”指示器并且您不希望通过数据绑定显示错误,那么是的, NotifyTaskCompletion<T>将是过度的。

It depends on how much you want to do data-binding. 这取决于你想要做多少数据绑定。 If you're happy with it all being in code, then that's fine: 如果你对代码感到满意,那就没关系了:

public async Task LoadMyData(IPeopleService peopleService)
{
   try
   {
      ... // Hide people display
      ... // Show loading indicator
      People = await peopleService.GetPeopleAsync();
      ... // Show people display
   }
   catch(Exception e)
   {
      ... // Show error indicator
   }
   finally
   {
      ... // Hide loading indicator
   }
}

Or, you can do it all with data binding, which makes your code simpler: 或者,您可以使用数据绑定完成所有操作,这使您的代码更简单:

// (wrapped in NotifyTaskCompletion)
public async Task LoadMyData(IPeopleService peopleService)
{
    People = await peopleService.GetPeopleAsync();
}

I've done it both ways, but I lean towards NotifyTaskCompletion<T> if I have a project that does a lot of asynchronous operations. 我已经完成了两种方式,但如果我有一个执行大量异步操作的项目,我倾向于NotifyTaskCompletion<T>

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

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