让我们想象一个非常简单的UI,其中有一个复选框列表。当你点击其中任何一个时:
1) 如果它没有被选中,它应该创建一个带有这个复选框名称的工作区(然后在该工作区中有更多的逻辑可用,但这与问题无关)。复选框自然会被选中;
2) 如果它已被选中,则应取消选中并销毁关联的工作空间。
实现这一点的直接形式是让View
查看单击的复选框的状态,并根据是否已被选中来执行viewModel.createWorkpace()
或viewModel.destroyWorkspace()
。但这意味着这个逻辑在View
中——我觉得最好把它放在ViewModel
中。
我读到,由于各种原因,ViewModel
不应该知道View
。但一件事是对View
(例如对象引用)没有物理依赖性,另一件完全不同的事是甚至没有意识到View
可能有复选框,如本例所示。
这给我的印象是,实际上,让View
和ViewModel
有那么大的区别并没有什么大的意义,事实上,ViewModel
离View
越近,就越容易在View
和ViewModel
之间绑定数据。
我应该如何处理这种情况,为什么?
感谢
这个想法是将视图和视图模型解耦。您应该能够单独实例化视图模型。造成这种情况的主要原因不是一些模糊的整洁或其他什么。主要原因是您可以通过实例化离散类来轻松地对代码进行测试。
视图应该查看与显示数据和允许用户交互有关的内容。视图模型应该具有作用于这些交互并向视图显示数据的代码。这并不意味着视图应该完全没有代码。但是,如果有代码,它应该是特定于视图的。使用行为等可重复使用的代码是个好主意。因为这样你就可以手动测试并证明它们是有效的。然后重新使用经过验证的代码。与转换器、验证器等类似。
所有代码。
所有这些都在视图中使用。
我认为理论上可以编写一个没有转换器、验证器或行为的应用程序。我从来没有见过一个严肃的商业应用程序没有这三个。
与其说视图对视图模型一无所知,不如说视图对模型一无所知。除非您也为视图实例化了视图模型,否则您不会实例化视图来进行测试。但这并不意味着你应该把所有的代码都塞进代码背后。
为什么会这样?因为MVVM之神会用他的闪电击倒你?没有。因为这会让未来的发展更容易吗?也许吧,但通常你不会注意到。
为什么?因为用视图的控件实例化视图非常缓慢。它们不可避免地有很多你无法模仿的依赖关系。它可能依赖于应用程序中的资源,因此您必须实例化应用程序并合并资源字典。视图通常取决于大量的库、图片、用户控件等。这些你都不能嘲笑。所以你需要一切。当你在一些测试运行程序中自动实例化所有东西并解决点击按钮等问题时。。。你的头会受伤,你会发现你理论上想每10分钟跑几秒钟的2000次测试比这几秒钟要长得多。如果在测试中实例化视图,就无法进行"正确"的TDD。
回答您的工作区复选框问题。这取决于工作空间到底是什么。
一种常见的模式是在绑定到每个复选框的ischecked属性的视图模型属性的setter中启动代码。这可能是在一个按复选框显示的视图模型中,该复选框有工作区的名称、类型或任何需要做的事情,即选中取消选中的东西。每一个都会对它正在创建的这些东西有某种引用,这样当被丢弃的值变为false时,它就可以处理它们或其他什么。