首页 > 解决方案 > MVVM 中的 ViewModel 应该与多少视图无关?

问题描述

让我们想象一个非常简单的 UI,其中有一个复选框列表。当您单击其中任何一个时:

1)如果它没有被选中,它应该创建一个具有此复选框名称的工作区(然后在该工作区中可以使用更多逻辑,但这与问题无关)。复选框自然会被选中;

2)如果它已经被选中,它应该变成未选中并且应该破坏相关的工作空间。

实现这一点的直接形式是View查看单击复选框的状态,并根据是否已选中或不执行viewModel.createWorkpace()or viewModel.destroyWorkspace()。但这意味着这个逻辑在View——我觉得最好把它放在ViewModel.

我读过由于ViewModel各种原因不应该知道View. 但是一件事是对(例如对象引用)没有物理依赖性,而另一件事则View完全不同,甚至不知道View可能有复选框,如本例所示。

它给我的印象是,实际上使ViewViewModel有很大不同并没有什么意义,事实上,越接近ViewModelView就越容易在View和之间绑定数据ViewModel

我应该如何处理这种情况,为什么?

谢谢

标签: wpfjavafxdesign-patternsmvvm

解决方案


这个想法是解耦视图和视图模型。您应该能够单独实例化视图模型。造成这种情况的主要原因不是一些模糊的整洁或其他东西。主要原因是您可以通过实例化离散类轻松地对代码进行测试。

视图应该查看与显示数据和允许用户交互相关的内容。视图模型应该具有作用于这些交互并将数据呈现给视图的代码。这并不意味着视图应该没有代码。但是,如果有代码,它应该是特定于视图的。使用可重用代码(例如行为)是个好主意。因为那时您可以手动测试这些并证明它们有效。然后重新使用经过验证的代码。与转换器、验证器等类似。

所有代码。

都在视图中使用。

我想理论上可以编写一个没有转换器或验证器或行为的应用程序。我从来没有见过一个严肃的商业应用程序没有这三个。

视图对视图模型一无所知比反之更重要。除非您还为它实例化了一个视图模型,否则您不会实例化视图来进行测试。这并不意味着您应该将所有代码都塞进代码后面。

为什么会这样?因为 MVVM 之神会用他的闪电击倒你?没有。因为这会让未来的发展更容易?好吧,它可能会,但通常不会引起你的注意。

那为什么?因为用它的控件实例化一个视图非常慢。它们不可避免地有很多你无法模拟的依赖关系。它可能依赖于应用程序中的资源,因此您必须实例化应用程序并合并资源字典。视图通常取决于大量的库、图片、用户控件等。您无法模拟这些。所以你需要一切。当您在某些测试运行程序中自动实例化所有内容并消除单击按钮等时...您的头会很痛,您会发现理论上您希望每 10 分钟运行几秒钟的 2000 次测试需要比那几秒钟长得多。如果你在测试中实例化视图,你就不能做“正确的”TDD。

回答您的工作区复选框问题。这取决于工作空间的真正含义。

一种常见的模式是在绑定到每个复选框的 ischecked 属性的 viewmodel 属性的 setter 中启动代码。这可能是在每个复选框呈现的视图模型中,该复选框具有工作空间的名称、类型或执行它所需的任何内容,即选中-取消选中的内容。每个都会对它正在创建的这些东西持有某种引用,因此它可以在 ischecked 值变为 false 时处理它们或任何东西。


推荐阅读