简体   繁体   English

与WPF MVVM中的TAP(async / await)异步

[英]Asynchrony with TAP (async/await) in WPF MVVM

I am looking for a best practice to the following setup. 我正在寻找以下设置的最佳实践。

A View is data bound to ViewModel (through WPF). View是绑定到ViewModel的数据(通过WPF)。 ViewModel updates View via INotifyPropertyChanged. ViewModel通过INotifyPropertyChanged更新视图。 Model updates ViewModel via events. 模型通过事件更新ViewModel。 The Model knows about stuff from the outside-world, like how to get stuff from the internet via WebClient, and how to retrieve data from a database. 模型知道来自外部世界的东西,比如如何通过WebClient从互联网上获取东西,以及如何从数据库中检索数据。

Getting and sending stuff to the outside-world should be done asynchronously in order for the UI (and by extension, the user) not to suffer from waiting on the outside-world. 获取和发送外部世界的东西应该异步完成,以便UI(以及扩展,用户)不会在外面世界等待。

What would be the best practice way to go about this? 最好的做法是什么?

1. The ViewModel should be responsible for calling model methods asynchronously. 1. ViewModel应负责异步调用模型方法。
This would have the advantage of being able to write stuff like 这将具有能够写出类似的东西的优点

GetWebPage(string url) {
  var result = await Model.GetWebPageAsync(url);
  Url = result.Url;
}

in the ViewModel where Url is a ViewModel property with INotifyPropertyChanged to update the View. 在ViewModel中, Url是一个ViewModel属性,使用INotifyPropertyChanged更新View。 Or even 甚至

GetWebPage(string url) {
  var result = await Model.GetWebPageAsync(url);
  _view.Url = result.Url;
}

where we can avoid the INotifyPropertyChanged all together. 在哪里我们可以一起避免INotifyPropertyChanged。 Which of these ways do you prefer? 您更喜欢以下哪种方式?

However, it might be more sensible to have the Model itself do the asynchronous work. 但是,让Model本身进行异步工作可能更为明智。 We might want to be able to use the Model without the View and ViewModel, while still having it work asynchronously. 我们可能希望能够在没有View和ViewModel的情况下使用Model,同时仍然可以异步工作。 Another argument is that, who knows better that the Model what stuff is best handled asynchronously. 另一个论点是,谁更清楚模型什么东西最好是异步处理。

2. The Model handles all the asynchronous stuff by itself. 2. Model自己处理所有异步内容。 The ViewModel code becomes more like ViewModel代码变得更像

GetWebPage(string url) {
  Model.GetWebPage(url);
}

and in the Model 在模型中

GetWebPage(string url) {
  var result = await Model.GetWebPageAsync(url);
  if (UrlChanged != null);
     UrlChanged(this, new UrlChangedEventArgs(url));
}

that the ViewModel can subscribe to, and update the View accordingly. ViewModel可以订阅,并相应地更新View。

Which of the ways do you think is the best practice? 您认为哪种方式是最佳做法?

The third way: view model makes asynchronous call, but it uses client-side service to retrieve web page, model itself is anemic (it knows nothing about outer world): 第三种方式:视图模型进行异步调用,但它使用客户端服务来检索网页,模型本身是贫血的(它对外部世界一无所知):

GetWebPage(string url) 
{
  var dataService = anyServiceLocator.GetService<IDataService>();
  var result = await dataService.GetWebPageAsync(url, Model);
  Url = result.Url;
}

This allows to change real data downloading algorithm, eg for testing purposes. 这允许改变实际数据下载算法,例如用于测试目的。

I believe the best practice for the scenario described will be the one you'll come up with - considering pros and cons of every approach - and that will be specific to your task (as the requirements change from task to task). 我相信所描述的场景的最佳实践将是你会想到的 - 考虑每种方法的优缺点 - 这将特定于你的任务(随着需求从一个任务变为另一个任务)。 Regarding the actual answer to the question, I believe there is no much difference. 关于问题的实际答案,我认为没有太大区别。 Although I'm thinking another approach now. 虽然我现在正在考虑另一种方法。 Think about parameterizing the asynchronous behavior of a Helper (maybe DownloadManager) object, which can be passed in to the VM as a parameter. 考虑参数化Helper(可能是DownloadManager)对象的异步行为,该对象可以作为参数传递给VM。 This will allow you to test both the VM and the Model easily without distinguishing the behavior, and test that behavior separately on DownloadManager. 这将允许您轻松地测试VM和模型,而无需区分行为,并在DownloadManager上单独测试该行为。

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

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