【问题标题】:MVVM - Patterns and PracticalityMVVM - 模式和实用性
【发布时间】:2015-11-04 19:57:28
【问题描述】:

我在 WPF 中使用 MVVM 已经有一段时间了。而且我在开发过程中学到了很多东西(从不使用它到开发了几个应用程序)

但是,最近我遇到了一些针对代码的 cmets,这让我想知道我是否以正确的方式做事。我当前的设置(大致)是这样工作的:

  • Model - 负责存储数据,使用数据验证 IDataErrorInfo 和脏跟踪
  • ViewModel - 负责获取数据(从像 模式)并对其进行格式化以供视图使用(例如 过滤、排序)也负责从 查看(保存、加载、过滤器更改等)
  • 视图 - 常见的 UI 内容

现在有人向我提到我应该从不在模型中包含业务逻辑,并且模型应该尽可能薄,视图模型应该负责处理诸如数据验证之类的事情和脏跟踪。

我在这方面看到了 cmets 和批评,人们反对和支持将逻辑放入模型中,我还没有看到这些笼统陈述的任何实际原因。所以我很想知道我是否应该重构我的设置。

此外,鉴于我确实将逻辑移至视图模型,我可以看到需要拥有多个视图模型,而我目前只有一个,例如:

  • Person - 型号
  • PersonViewModel - 处理脏跟踪、数据验证等
  • PersonsViewModel - 处理获取 PersonViewModels 的集合, 过滤等
  • PersonsView - 用户界面

这似乎有点多余,但也许我误解了一些东西。我真正在寻找的是以某种方式执行此操作的一些实际原因,或者这是另一个论点,例如在 MVVM 中使用代码隐藏(纯粹的观点,没有什么理由等)

【问题讨论】:

  • 您说 VM 负责获取数据。这可能是真的,也可能不是。这取决于什么最适合您,但 MVVM 设计模式确实指定了它。例如,在创建第一个视图模型之前,您可以在应用程序启动时加载所有数据。或者您可以称您为模型,其中包括来自视图模型的数据访问。
  • 这只是我当前的设置,我的视图模型负责与存储库通信,而存储库又与 WCF 服务通信,但我有其他应用程序的工作方式不同。
  • “模型内部永远不会有业务逻辑” - 以前从未听说过与 MVVM 相关的内容;阅读此类文章/讨论会很有趣。
  • 在典型的互联网时尚中,我终生无法找到我读过的那篇文章。我可以找到一句话永远不要把它放在视图模型中。虽然我提到接收的 cmets 不在线。

标签: c# wpf mvvm


【解决方案1】:

MVVM 的高级描述:

  • 视图:用户界面

  • 模型:业务逻辑和数据(例如领域模型+存储库,或者事务脚本+POCO实体等)

  • ViewModel:数据以这种形式发布到视图,很容易从视图中消费。维基百科的定义说:视图模型是视图的抽象,它公开了公共属性和命令。

我喜欢 Practical MVVM Manifesto (archived version) 原则:简单性、可混合性、可设计性、可测试性。

这是非常高级和抽象的描述,这就是为什么您可能会发现许多 MVVM 变体。无论您选择哪种 mvvm 样式,请牢记责任和原则,您应该没问题。尽量避免复杂性。 MVVM 不是灵丹妙药,单一设计模式无法涵盖所有​​场景。一种 mvvm 实现可能适用于一种应用程序,但不适用于另一种应用程序。例如,我为每个新项目从头开始构建我的 mvvm 架构,以确保最适合


当涉及到责任时:

以验证为例: 密码和重复密码输入应该相等的验证逻辑显然是表示逻辑,应该出现在视图模型中。另一方面,可能存在业务规则,即密码必须包含至少一个特殊字符。这个逻辑应该驻留在模型中,但是您可以在视图模型中公开它以便从视图中轻松使用。这是一个业务逻辑,但您可能需要以某种方式呈现它。

如果您的应用程序仅使用 Web 服务来检索和存储,那么您的模型可能只是数据访问组件。


这里有几个资源:

维基百科:https://en.wikipedia.org/wiki/Model_View_ViewModel.

MVVM 是 Martin Fowler 的 MVP 模式的变体,您可能会发现它也很有用:http://martinfowler.com/eaaDev/PresentationModel.html

MSDN(模式与实践):https://msdn.microsoft.com/en-us/library/hh848246.aspx

【讨论】:

  • 谢谢,这是一个全面的答案,您认为 IsDirty 跟踪是视图模型还是模型的责任?目前我在模型上有它,但有人告诉我这是视图模型的责任。
  • @user1412240 好的。为什么你需要了解脏污?总的来说,我发现划分逻辑的一个好方法是重用和测试。该模型是业务逻辑,即使您编写 MVC 网站也应该可用。 VM 和 V 之间的区别在于 VM 是可单元测试的。
  • 好吧,看到这一切后想一想,我猜这将是 VM 角色,因为我使用 IsDirty 启用保存按钮,阻止导航而不保存(或至少通知用户)。都是一个接口级逻辑
  • 嗯,这取决于。如果您的 PersonViewModel 只是公开了已经具有 changetracking 的 Person 模型,并且您直接绑定到 Person,那就没问题了。在其他情况下,您可能只想在单击保存按钮时更新 Person 的属性。如果您只想在某些内容发生更改时启用保存按钮,则需要在 viewmodel 中实现更改跟踪。我建议从最简单的方法开始,它不会破坏高级 mvvm 原则,但要为变化做好准备。
  • 抱歉,回复晚了,我没有收到此评论的通知。我总是为变化做好准备,这就是导致我提出这个问题的原因哈哈,我认为我更喜欢 VM 上的更改跟踪,因为更改跟踪不会在 WPF MVVM 应用程序之外使用,因此不属于模型
【解决方案2】:

我喜欢将模型层视为与应用程序托管方式无关的任何事物(即独立于 WPF)。它是一个或多个 dll,代表业务领域和需要在其中执行的操作。如果获取这些相同的 dll 并在 Web 应用程序、Windows 服务等中使用它们是有意义的,那么这通常表明模型和 ViewModel 之间的拆分是适当的。

【讨论】:

  • 对,如果我理解正确的话。您的原因是可重用性,以及跨服务层使用相同模型类的能力。好的,这是我可以落后的一个很好的理由,谢谢
  • 在概念上是的。毕竟 MVVM 中的“模型”与 MVC 和许多其他设计模式中的模型相同。您可能对here 的意见感兴趣 - 关于 MVC 的类似问题。
  • 有趣,这与我收到的关于将逻辑排除在模型之外的 cmets 的反面,但再次对我来说答案很有意义。看来这一切都归结为个人喜好和应用程序的需求。我想我的困惑是需要额外的没有视图的视图模型(我一直明白视图模型仅用于视图)
  • 我完全同意这一点,尽可能多的业务逻辑应该放在模型中,只是想发布完全相同的推理。
  • “将逻辑排除在模型之外”-也许他们在谈论将逻辑排除在实体之外-关于贫血的实体。这意味着实体没有任何行为。在一些简单的场景中,行为可能纯粹在视图模型中,但更复杂的场景需要重用行为,并且您需要创建某种表示行为的业务类 - 例如事务脚本。请注意,实体与模型不同。在这种情况下,模型既是贫血实体,也是交易脚本。
【解决方案3】:

您的问题没有简单的答案。最简单的答案是模型和视图模型应该包含您应该单元测试的代码。模型和视图模型之间的分离不太明显。我喜欢使模型尽可能简单,并将其限制为与服务器层交换的任何内容。视图模型应该封装模型,并提供任何附加功能(业务逻辑和抽象表示逻辑),以便您可以保持表示层尽可能简单(声明性,在 WPF XAML 的情况下)。

【讨论】:

  • 您喜欢保持模型纤薄的事实仅仅是个人选择吗?这是否也意味着我对多个视图模型的假设是您选择做事的方式?
  • 这是个人选择和对该主题的研究的混合体。是的,我经常有多个视图模型用于单个模型 - 视图模型是特定于视图的,而模型更通用。
  • 只是一个快速的清理,你会说我的例子(Person、PersonVM、PeopleVM)是你会做的吗?鉴于此时没有personview?
  • 在不知道各种模型包含哪些数据的情况下,我会说是的。虽然,如果人员视图的唯一目的是显示 Person 中包含的数据,那么 PeopleVM 包含 Person 模型列表可能就足够了。
  • 是的,我可以接受,这个想法就是我想在那个视图中编辑的内容,直接从 gridview 说,你几乎回答了这个问题。谢谢。
【解决方案4】:

我是这样看的:

Model - 可以传递的对象。用于通信的不同层之间的通用类型。

ViewModel - 专为视图创建。这应该包含 UI 逻辑,例如,数据注释等将放在此处。您也可以在这里调用您的 Web 服务方法(假设您的实际业务逻辑位于外观层中,或者您的数据库逻辑位于不同的层/项目中)来填充视图、下拉列表等。您最终可能会得到多个这些查看,具体取决于您的设计。

查看 - 仅限用户界面。

我不怕在 ViewModel 中进行外部调用

【讨论】:

  • 好吧,这一切都是有意义的,似乎是主要的思想流派,但是拥有一个没有相应视图的视图模型又有什么意义呢?
  • 一个 ViewModel 可能指向某种控制器。该控制器是主视图的一部分
猜你喜欢
  • 2013-08-16
  • 2018-03-25
  • 1970-01-01
  • 2011-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-05
相关资源
最近更新 更多