【问题标题】:WPF MVVM vs Razor Page MVVMWPF MVVM 与 Razor 页面 MVVM
【发布时间】:2019-03-11 11:31:30
【问题描述】:

WPF 中的 MVVM 模式非常强调将 ViewModel 与 UI 完全分离,理想情况下,代码隐藏文件中没有或只有很少的内容。这允许将 ViewModel 重新用于不同类型的界面。

Razor Pages 中的 MVVM 模式具有作为 ViewModel 的代码隐藏,并通过 OnGet 和 OnPost 方法与 Web 逻辑紧密耦合。

因此,精心设计的解耦 WPF ViewModel 不能用作 Web ViewModel(或者也许可以网页模型中使用?)

有什么我遗漏的吗,为什么 WPF 中的 MVVM(解耦)和 Razor Pages 中的 MVVM(耦合)之间存在这种差异?

如果我们将 Razor Pages 方法应用于 WPF,那么代码隐藏将成为 ViewModel——我从未见过有人推荐过。

【问题讨论】:

  • 据我所知,MVVM 是关于从 Views 中解耦 Models,而不是从 Views 中解耦 ViewModels :\

标签: c# .net wpf asp.net-core mvvm


【解决方案1】:

为了清楚起见:WPF 在视图和视图模型之间引入了耦合,就像 Razor Pages 所做的那样。视图模型是一个数据表示层,目的是打破视图和模型之间的依赖关系。因此可以在不修改任何模型的情况下更改视图。然后,视图模型本身与模型耦合,因为它获取所需的数据(例如,从服务或数据库中)。 通过让视图模型实现抽象 PageModel 并通过提供适当的可选操作处理程序(例如 OnGet())遵循约定,此行为在 Razor 页面中以统一模式实现。每当为页面发出 HTTP 请求时,框架都会调用这些处理程序。您将根据请求方法(例如 GET、DELETE、POST、PUT ......)获取或操作模型数据,然后将其呈现给视图。该约定描述了这些处理程序的命名模式,以便框架可以识别它们。

因此,您会发现 WPF MVVM 和 Razor Pages MVVM 中的层之间的耦合程度相同。由于 RazorPages 中的视图模型封装了特定页面的上下文,因此源文件命名遵循命名约定(“页面名称.cshtml.cs”)以使关系在文件系统中可见。它不是像 WPF 中视图的 partial 类文件那样的代码隐藏文件。

【讨论】:

  • 视图模型是一个数据表示层,目的是打破视图和模型之间的依赖关系 不完全正确,你描述的是 MVC。 MVVM 将 VIew 从表示逻辑中分离出来,并支持从 Windows 窗体时代(txtName.Text 读取或设置值)中没有意大利面条代码的双向绑定。它是由 Microsoft 专门为 WPF 引入(和发明)的。在 WinForms 中,您在代码隐藏中有很多与格式化值和检索/更新 UI 元素相关的代码。 MVVM 是为了解决这个问题而发明的。在 ASP.NET Core 中,VM 只是简化为没有任何逻辑的 DTO 类
  • WPF/MVVM 中的表示逻辑通常涉及更新其他控件内容(通过数据绑定和INotifyPropertyChanged 解决),更新文本字段的状态(活动/非活动,按钮,通过 @ 处理) 987654326@ 和 CanExecute)或协调用户输入与后台服务(命令调用服务以获取或提交数据 - 由 MVC 中的控制器完成)。大多数这些东西不适用于服务器端的 Web 应用程序(但可以应用于客户端的 Web 应用程序)。 MVVM 的目标是在 UI 更改或返工时重用它
  • MVVM 是 MVP 的一种形式,它是 MVC 的一种形式。我说数据表示层是为了强调它是模型数据本身的中间层。 MVVM 的主要目标(与 MVP、MVC 相同的目标)是将视图与模型或业务逻辑解耦。数据绑定只是实现这一点的机制。它是 MVP 的一种变体,它使用绑定来使 Presenter(或 Controler)和 View 之间的依赖关系单向。
  • 不,DataBinding 是引入 MVVM 的主要原因。在 WPF 存在之前没有 MVVM。它专为 WPF 数据绑定功能而设计。后来该模式被其他框架采用,但它最初是为 WPF 及其数据绑定设计的。它由两位 Microsoft 工程师 Ken Cooper 和 Ted Peters 发明/定义/描述:en.wikipedia.org/wiki/Model–view–viewmodel#Rationale
  • 我从未说过 MVVM 在 WPF 之前就存在。我只是说它是从 MVP 演变而来的。 MVP 像 MVC 有一个指向视图的依赖箭头(在依赖图或 UML 模型中)。通过引入绑定机制,他们设法移除了这个箭头。演示者与视图变得更加分离。在 MVVM 中,所有依赖箭头现在都指向同一个方向,并且远离视图。
【解决方案2】:

当有 MVC(模型-视图-控制器)时,我不确定您为什么坚持使用 Razor 页面。

您应该改用 MVC 模式。你得到了相同的剃刀语法,但解耦了。

Razor Pages 是作为 WebForms 的后继形式引入的(WebForms 本身试图模仿 Windows 窗体,而这两者都不是为了解耦)。

如果我们回到几年前,MVVM 是为了使用 WPF 的双向模型绑定的全部功能,它充当 UI 和应用程序层之间的单独层,可以将表示逻辑(逻辑紧密耦合到 Presentation,这是一个 UI 关注点,而不是与 UI 解耦的应用层)。

出于这个原因,MVVM 的 ViewModel 还具有(除了模型绑定的属性),诸如命令之类的东西,并且可能是导航感知的(即通过 Prism 的INavigationAware 接口)。

在这种情况下,ViewModel 在服务器端的 Web 应用程序中没有多大价值,因为 HTTP 本身是无状态的,ViewModel 保持状态。

因此,MVC 中的 ViewModel 被简单地简化为 DTO(数据传输对象),它具有基本的验证(通过验证属性)。 MVC 应用程序中的 ViewModel 没有任何表示逻辑,因为它呈现为 HTML 并且大多数表示逻辑通过 JavaScript 在外部发生(单击按钮时会发生什么,如何为用户格式化日期或货币)。

话虽如此,在 ASP.NET Core 应用程序中您并不真正需要完整的 ViewModel,至少对于服务器端部分来说不需要。但是,如果您使用的是客户端技术(Angular、Vue.js、React),您可以利用 ViewModels 来增强功能并将其与 View 分离。

事实上,angular components 几乎是 ViewModel,完成与 MVVM 模式中的 ViewModel 相同的任务(可以向其中注入服务,具有 1-way 或 2-way 绑定、输入验证和一个将表示逻辑放入他们)。

TL;DR:您并不真正需要 ViewModel,因为它们是在 MVVM 中定义的,只需要类似 DTO 的类,以便在 (Razor)View 模板中更轻松地使用它们。并且不要使用 Razor Pages 进行解耦。

【讨论】:

  • 当我将@model MyModel 添加到我的视图中时,这不是“耦合”我的视图和模型吗?在这一点上,Razor Pages 和 MVC 之间绝对没有区别。只是表达方式不同。
  • MVC/MVVM 中的“模型”不仅仅是“DTO 类”。 M-V-VM/M-V-C 是层,而不是具体的类。例如,NavigationService 是 View 的一部分,即使它是用代码编写的。它不像“View = XAML 没有别的”。 MVC 意义上的模型是“所有不是视图或控制器的东西”,它还包括你的所有服务。这取决于您与@model MyModel 绑定的内容。绑定你的 EF 实体?那是错误的方法。竞标您的 DTO/ViewModel?那你就好了
  • 我已经阅读了很多关于 MVC 与 Razor 页面的文章,大多数人都推荐 Razor 页面,除非它是 Web API 或单页应用程序。他们说 MVC 控制器类像病毒一样增长,代码散布到各种地方——从这个意义上说,Razor 页面具有更清晰的关注点分离。甚至微软也在为基于页面导航的网站推荐 Razor 页面。
  • @EtienneCharland MVVM、MVP 或 MVC 模式的目标不是重用控制器或视图模型,而是重用应用程序的业务逻辑。您不想在每次修改或替换视图时都修改模型。它还使自动化 UI 测试成为可能,这也是一个巨大的收获。当视图与模型耦合时,没有它就无法测试视图。假设您的模型由服务和数据库组成,这可能会产生巨大的影响。
  • @EtienneCharland 如果您不需要可测试性,或者您的应用程序很小或 UI 永远不会改变(例如设计或新的导航路径或结构),您可以在没有这些模式的情况下进行公平开发。您的评价和您的个人决定。视图模型只是使视图不必直接访问模型成为可能。它打破了依赖。这两者之间。同时模型不必关心数据的呈现。
猜你喜欢
  • 1970-01-01
  • 2017-05-12
  • 1970-01-01
  • 2011-06-19
  • 1970-01-01
  • 2018-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多