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

时间:2012-10-29 10:15:09

标签: c# wpf mvvm

我正在寻找以下设置的最佳做法。

View是绑定到ViewModel的数据(通过WPF)。 ViewModel通过INotifyPropertyChanged更新视图。模型通过事件更新ViewModel。模型知道来自外部世界的东西,比如如何通过WebClient从互联网上获取东西,以及如何从数据库中检索数据。

获取和发送外部世界的东西应该异步完成,以便UI(以及扩展,用户)不会在外面世界等待。

最好的做法是什么?

1。 ViewModel应负责异步调用模型方法。
这样可以编写像

这样的东西
GetWebPage(string url) {
  var result = await Model.GetWebPageAsync(url);
  Url = result.Url;
}

在ViewModel中Url是ViewModel属性,使用INotifyPropertyChanged更新View。 甚至

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

我们可以在一起避免INotifyPropertyChanged。您更喜欢以下哪种方式?

但是,让Model本身进行异步工作可能更为明智。我们可能希望能够在没有View和ViewModel的情况下使用Model,同时仍然可以异步工作。另一个论点是,谁更清楚模型什么东西最好是异步处理。

2。模型自己处理所有异步内容。 ViewModel代码变得更像

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

并在模型中

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

ViewModel可以订阅,并相应地更新View。

您认为哪种方式是最佳做法?

2 个答案:

答案 0 :(得分:3)

第三种方式:视图模型进行异步调用,但它使用客户端服务来检索网页,模型本身是贫血的(它对外部世界一无所知):

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

这允许改变实际数据下载算法,例如,用于测试目的。

答案 1 :(得分:0)

我认为所描述场景的最佳实践将是您将要提出的方案 - 考虑每种方法的优缺点 - 并且这将特定于您的任务(因为需求随任务而变化)。 关于问题的实际答案,我认为没有太大区别。虽然我现在正在考虑另一种方法。考虑参数化Helper(可能是DownloadManager)对象的异步行为,该对象可以作为参数传递给VM。这将允许您轻松地测试VM和模型,而无需区分行为,并在DownloadManager上单独测试该行为。