通过


WinUI 应用的 MVVM 性能提示

本主题讨论与 MVVM、绑定和视图组合相关的 WinUI 应用的一些性能注意事项。

Model-View-ViewModel (MVVM) 模式

在许多 WinUI 应用中,Model-View-ViewModel(MVVM)模式是一种常见模式。 (MVVM 与 Fowler 对模型View-Presenter 模式的描述非常相似,但它是针对 XAML 定制的)。 MVVM 模式的问题在于,它可能会无意中导致具有过多层和过多分配的应用。 MVVM 的动机就是这些。

  • 职责分离。 将问题划分为较小的部分总是有帮助的,而 MVVM 或 MVC 等模式是将应用(甚至单个控件)划分为较小的部分的方法:实际视图、视图(视图模型)的逻辑模型和独立于视图的应用逻辑(模型)。 具体而言,让设计人员使用一个工具拥有视图是一种流行的工作流,开发人员使用另一个工具拥有该模型,设计集成器使用这两种工具拥有视图模型。
  • 单元测试。 可以在不依赖视图的情况下对视图模型(以及模型)进行单元测试,这样无需依赖于创建窗口、驱动输入等操作。 通过缩小视图,可以测试大部分应用,而无需创建窗口。
  • 适应用户体验变化的灵活性。 视图往往看到最常见的更改和最晚的更改,因为用户体验会根据最终用户反馈进行调整。 通过将视图分开,可以更快地适应这些更改,并且对应用的改动更少。

MVVM 模式有多个具体定义,以及有助于实现它的第三方框架。 但是,严格遵循任何模式变体可能会导致应用程序的开销远远超过其合理性。

  • XAML 数据绑定({Binding} 标记扩展)部分是为了实现模型/视图模式而设计的。 但 {Binding} 带来了非普通的工作集和 CPU 开销。 创建 {Binding} 会引起一系列内存分配,更新绑定目标可能会导致反射和装箱操作。 在 WinUI 中,使用 {x:Bind} 标记扩展解决了这些问题,该扩展在生成时编译绑定,并在 WinUI 示例和生产应用中广泛使用。 建议: 使用 {x:Bind}。
  • MVVM 中常用的是使用 ICommand 连接 Button.Click 到视图模型,例如常见的 DelegateCommand 或 RelayCommand 帮助程序。 这些命令是额外的资源分配,包括 CanExecuteChanged 事件侦听器、对工作集的增加,以及页面启动/导航时间的增加。 建议: 作为使用方便的 ICommand 接口的替代方法,请考虑将事件处理程序放在代码隐藏中,将它们附加到视图事件,并在引发这些事件时对视图模型调用命令。 你还需要添加额外的代码,以在命令不可用时禁用按钮。
  • 在 MVVM 模式中,通常会创建一个包含所有可能 UI 配置的页面,然后通过将 Visibility 属性绑定到 VM 中的属性来折叠树的某些部分。 这增加了不必要的启动时间,并可能添加到工作集(因为树的某些部分可能永远不会变得可见)。 建议: 使用 x:Load 属性 功能将树中不必要的部分推迟启动。 此外,为页面的不同模式创建单独的用户控件,并使用后台代码来仅保留加载所需的控件。