【问题标题】:Is async/await useless in MVVM? [closed]async/await 在 MVVM 中没用吗? [关闭]
【发布时间】:2012-11-09 08:00:39
【问题描述】:

在 ViewModel 通过 INotifyPropertyChanged 事件更新 View 的 MVVM 中,async/await 的酷特性似乎没有太多空间;在调用者捕获的同步上下文上执行延续。

那么,如果是这样,那么谁会在基于现代 UI 的应用程序中真正使用 async/await 的功能呢?在这种情况下,“谁”也可以表示什么模式,例如MVC 变体。

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

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

然而,在捕获的 syncContext 上运行它并没有太大帮助。 实际上,我们可以将所有这些都放在模型中。

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

现在,我们真的不希望同步上下文成为捕获的对象。

【问题讨论】:

  • 基于任务的异步模式,但实际上我只是指 C#5 中的 async/await 功能。
  • 为什么没用?你可以等待各种不同的事情。更新 UI、获取数据、监听消息...
  • 这将是无用的,因为在 MVVM 中不需要在调用上下文上执行回调的整个功能,因为更新是通过事件完成的。
  • 那些需要执行大量工作然后更新属性的命令呢?
  • 所谓的空间不足从何而来?与其在阻止 UI 线程的同时做一些需要一段时间的事情,不如释放 UI 线程并在其他地方完成工作。它与使用工作池没有什么不同,但更容易编写,并且你可以说出你的延续必须在哪里执行。而且您已经在使用事件来通知 UI。

标签: c# .net


【解决方案1】:

实际上,在 UI 同步上下文中提出INotifyPropertyChanged.PropertyChanged必需的数据绑定。

async / await 确实强制您区分 properties(表示当前状态并且始终同步)和 commands(表示操作并且可以是同步的或异步的)。属性获取器和设置器不能async,因此您的示例代码不能使用“异步集”。

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

一个现实的例子是让 VM 属性在内存中设置 M 个属性,并有一个 SaveCommand 和一个 async 处理程序。让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 应用程序中最具挑战性的部分。

【讨论】:

  • 我的印象是 INPC 是一个事件,它在 UI 线程上推送一条消息,导致 UI 线程从 VM 中提取相关属性的值。
  • INPC 只是一个常规活动。除非您专门以这种方式实现它,否则它不会跳转线程(我不推荐,但有些人确实选择这样做)。
  • 很好的答案。帮助巩固了 C# 中异步操作的一些整体概念。
  • “除非您专门以这种方式实现它,否则它不会跳转线程” - 确实如此。是的,从更广泛的意义上说,处理跨线程问题的 INPC 接口没有什么特别之处。但是 WPF 对接口的 use 确实如此。如果在错误的线程中引发了PropertyChanged,则 WPF 绑定将自动分派到 UI 线程以处理该事件。 IE。 WPF 事件处理程序本身执行跨线程调度。恕我直言,这是正确回答上述问题的重要一点。
猜你喜欢
  • 2017-06-30
  • 2013-05-26
  • 2013-01-12
  • 1970-01-01
  • 1970-01-01
  • 2017-04-10
  • 2019-09-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多