在MVVM中,ViewModel是否应该引用View?

14
在MVVM(Model-View-ViewModel)模式中,ViewModel是否应该引用view?我认为不应该。但是以下情况应该如何处理?我有一个视图,其中标签控件作为主容器,这个视图的viewmodel实现了一个命令来向标签控件添加新的选项卡。简单的方法是允许viewmodel引用view,然后在命令实现中在view中编程地添加新的选项卡到标签控制中。这似乎是错误的。我应该如何将tabcontrol绑定到viewmodel,然后实现数据/控件模板来添加新的标签页。希望这对某个人有些意义 :)
4个回答

17
在“纯”MVVM中,ViewModel不应该真正引用View。然而,通常情况下,在View中提供某种形式的接口让ViewModel与之交互会更加方便。
然而,我发现我几乎再也不这样做了。另一种方法是在View中使用某种附加属性或混合行为,并将其绑定到ViewModel属性。这使得您可以将View逻辑保持在View内部100%。此外,通过为此创建行为,您创建了一个可重复使用的类型,可用于处理每个ViewModel->View交互。我强烈推荐这种方法,而不是在ViewModel中具有任何View逻辑。
为了演示这种技术,我编写了一个Expression Code Gallery的示例WindowCloseBehavior。它演示了如何在View中使用Behavior绑定到ViewModel属性来处理控制窗口生命周期的操作,包括防止其关闭等。

8

Reed和Dan涵盖了一般的方法,但是针对您的特定情况,TabControl是一个ItemsControl,因此可以将其ItemsSource绑定到ViewModel中表示要显示的选项卡集合的数据集合。然后,每种类型的选项卡的UI可以由特定于项目的数据类型的DataTemplate表示(使用DataType或DataTemplateSelector)。您可以随时从VM中添加或删除数据项,并且选项卡会自动更新,而VM不知道任何关于TabControl的信息。


所有其他答案都很好。这个答案只涵盖了我特别想做的事情。我甚至找到了一种方法,在不通过视图引用的情况下,通过将我的VM绑定到我的集合中的lastAdded模型的属性来设置视图模型中的选定项。非常巧妙... - Johan

6
我发现在View上暴露一个处理View特定功能的接口通常是一个有帮助的折中方案。这是处理纯绑定难以实现的事情的好方法,例如指示表单关闭、打开文件对话框(虽然这通常被放在自己的服务接口中)或与不适合数据绑定的控件交互(如你提供的例子)。
使用接口仍然可以保持View和ViewModel基本上解耦,并使您能够在测试期间模拟特定的IView。

0
我们中有人忽略了一些显而易见的东西。你的选项卡控件是一个ItemsControl。你应该将选项卡控件的ItemsSource绑定到视图模型中的一个可观察集合。当你在视图模型中处理命令以添加选项卡时,你只需向此集合添加一个新元素,然后,你就已经向控件添加了一个新选项卡。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接