在MVVM中async / await是无用的吗?

在MVVM中,ViewModels通过INotifyPropertyChanged事件更新视图,async / await的酷炫function似乎没有多大空间; 在调用者的捕获同步上下文上执行继续。

那么,如果是这种情况,那么谁将在现代基于UI的应用程序中实际使用async / await的function? 在这种情况下,“谁”也可以表示什么样的模式,例如MVC变化。

我认为以下是使用TAP的好方法

ViewModel.Age { set { await Model.SetAge(value); NotifyPropertyChanged("Age"); } } 

但是,在捕获的syncContext上运行此操作并没有多大帮助。 实际上,我们可以将所有这些都放在模型中。

 Model.Age { set { await SetAge(value); NotifyPropertyChanged("Age"); } } 

现在,我们真的希望syncContext不是捕获的。

实际上,在UI同步上下文中引发INotifyPropertyChanged.PropertyChanged是数据绑定所必需的。

async / await会强制您区分属性 (表示当前状态并始终是同步的)和命令 (表示操作,可以是同步或异步)。 属性getter和setter 不能async ,因此具有“异步集”的示例代码不是一种可能的方法。

async启用异步命令。 您可以使用命令绑定来异步处理路由命令,或将async委托传递给DelegateCommand ,或使用您自己的ICommand实现。 无论您采用哪种方式,最终都会得到一个async void命令事件处理程序。

一个现实的例子是让VM属性在内存中设置M属性,并使用带有async处理程序的SaveCommand 。 让async处理程序与其他VM属性( SaveInProgress或可能与其他async处理程序共享的公共Busy )交互是很常见的,这样UI可以在命令正在进行时做出适当的响应(通常至少会导致CanExecute返回false )。

所以你的async处理程序最终会看起来像:

 private async void SaveCommandExecute() { try { // Set VM property; updates View appropriately. Busy = true; // Do the actual saving asynchronously. await Model.SaveAsync(); } catch (Exception ex) { // Update the VM with error information. Error = ex.Message; } finally { // Let the VM know we're done. Busy = false; } } private void SaveCommandCanExecute() { return !Busy; } 

请注意,VM属性( ErrorBusy )在捕获的UI同步上下文中更新。


这说明了async MVVM的核心概念:命令可能是async ,但属性(如Busy )始终表示当前状态。

如果您要将async添加到现有的MVVM应用程序中,您会发现自己有几个额外的属性指示业务,也可能还有进度更新(例如,完成百分比)。 根据您的应用程序,您可以同时允许多个异步操作。 您需要考虑将这些信息添加到视图中的好方法; 我发现这是async MVVM应用程序中最具挑战性的部分。