今天我和同事讨论了如何正确实现MVVM模式。对于一个页面,我遇到了以下情况:
- 页面显示用户可以提交的表单(页面的主要目标是此表单)
- 除了表单之外,在右上角还有一个图像,用户可以点击它来显示菜单选项
- 这个图像和将要显示的菜单被编程如下:
- 在视图上定义图像,点击图像将绑定到命令
- ViewModel定义这个命令的逻辑 这个逻辑将实例化一个新的类
- 这个类实例化了一个特定的ContentView,它代表了一个弹出窗口
- 弹出窗口被推送到堆栈上,并显示给用户
我现在的问题是:这违反了MVVM模式吗?
我一直在阅读关于MVVM模式的微软文档,以找出它是否违反了MVVM模式,我个人的观点是这个架构违反了模式。我这样做的理由是ViewModel在这种情况下直接引用了一个ContentView,这与根据模式应该是完全相反的,因为ContentView可以被看作是View。我对这个架构的修复是,一旦ContentView应该打开,ViewModel就会给出一个信号,并通过打开ContentView本身来响应这个信号。通过这种方式,你保持了ViewModel和View之间的分离,并且让View负责在UI中显示元素。
我同事的意见是,这并不违反MVVM模式,因为有问题的UI元素(弹出窗口)是当前视图的外部元素。如果它是当前视图已知的元素(例如,是表单的一部分的元素),那么ViewModel与它的呈现方式无关。
但是因为这是一个被实例化的外部元素,所以当前视图已经并且不应该知道新元素是如何显示的。即使对于新元素,这也仅限于暴露/给出需要显示的数据(popupTitle, popupContent),但不考虑它实际上是如何显示的,因为这是"新"视图的任务。
所以这个问题的核心是:ViewModel是否应该声明特定的(Content)视图,应该在它检查逻辑为真或假之后显示?或者应该显示的特定(内容)视图由视图而不是ViewModel引用?
你同事错了。UI元素的外来性是无关的。
为了严格遵循MVVM, VM类不包含对任何UI类的引用。时期。
相反,VM类操作MODEL对象表示所需的UI。这些被传递(可能是通过绑定)给View类,View类负责将每个Model转换为UI元素。先进-意见-争议
有时可以通过创建一个Interface
来公开View类的非ui属性来解决困难的情况。
View类可以实现该接口,而VM类可以"知道"。这个接口。这允许View对象在VM之间传递,而不会违反严格的划分。
它还保持可测试性,因为一个"嘲弄"。object(实现该接口的对象)可以替换为View对象。
但是View对象的创建仍然需要在"hands off"中完成。也许是通过"工厂"。所以VM类永远不会引用任何UI类。
然而:你所提到的都不应该需要像这样先进的东西。创建和操作MODELS;让UI类来创建UI元素。