在MVVM中,ViewModels通过INotifyPropertyChanged事件更新视图,async/await的酷炫功能似乎没有多大空间; 在调用者的捕获同步上下文上执行继续.
那么,如果是这种情况,那么谁将在现代基于UI的应用程序中实际使用async/await的功能?在这种情况下,"谁"也可以表示什么模式,例如MVC变化.
我认为以下是使用TAP的好方法
ViewModel.Age
{
set {
await Model.SetAge(value);
NotifyPropertyChanged("Age");
}
}
Run Code Online (Sandbox Code Playgroud)
但是,在捕获的syncContext上运行此操作并没有多大帮助.实际上,我们可以将所有这些都放在模型中.
Model.Age
{
set {
await SetAge(value);
NotifyPropertyChanged("Age");
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我们真的希望syncContext不是捕获的.
Ste*_*ary 29
实际上,INotifyPropertyChanged.PropertyChanged在UI同步上下文中引发数据绑定是必需的.
async/ awaitdo强制您区分属性(表示当前状态并始终是同步的)和命令(表示操作,可以是同步或异步).物业getter和setter方法不能成为async,所以有"异步设置"您的示例代码是不是一个可行的方法.
async启用异步命令.您可以使用命令绑定来异步处理路由命令,或将async委托传递给a DelegateCommand,或使用您自己的ICommand实现.无论你采用哪种方式,最终都会得到一个async void命令事件处理程序.
一个现实的例子是让VM属性在内存中设置M属性,并SaveCommand使用一个async处理程序.让async处理程序与其他VM属性交互(SaveInProgress或者可能Busy与其他async处理程序共享)是很常见的,这样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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,VM属性(Error和Busy)在捕获的UI同步上下文中更新.
这说明了asyncMVVM 的核心概念:命令可能是async,但属性(例如Busy)总是表示当前状态.
如果您要添加async到现有的MVVM应用程序,您会发现自己有几个额外的属性指示业务,也可能还有进度更新(例如,完成百分比).根据您的应用程序,您可以同时允许多个异步操作.您需要考虑将这些信息添加到视图中的好方法; 我发现这是asyncMVVM应用程序中最具挑战性的部分.