在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属性( Error
和Busy
)在捕获的UI同步上下文中更新。
这说明了async
MVVM的核心概念:命令可能是async
,但属性(如Busy
)始终表示当前状态。
如果您要将async
添加到现有的MVVM应用程序中,您会发现自己有几个额外的属性指示业务,也可能还有进度更新(例如,完成百分比)。 根据您的应用程序,您可以同时允许多个异步操作。 您需要考虑将这些信息添加到视图中的好方法; 我发现这是async
MVVM应用程序中最具挑战性的部分。