MVVM:GUI 和 ViewModel 之间的真正分离

Posted

技术标签:

【中文标题】MVVM:GUI 和 ViewModel 之间的真正分离【英文标题】:MVVM: True seperation between GUI and ViewModels 【发布时间】:2015-04-23 09:00:02 【问题描述】:

我正在寻找 MVVM 视图和 ViewModel 之间 TRUE 分离的良好示例/方式。我什至不想在 View 中引用 ViewModel 或其他方式。


问题描述

只是为了可视化我的问题: 想象3个独立的项目; GUI(视图)、逻辑(ViewModels)和模型。

概览:

如何设置解决方案,以免导致循环引用?

接近

我的一个想法是使用第四个项目作为某种经纪人:

我不喜欢的是 Logic(ViewModel) 项目在这种情况下将是主要项目。或者也许没关系,我只是有奇怪的感觉。

你们觉得呢?


编辑

感谢 Charles Mager,我发现了一篇非常有趣的文章,其中预定义了映射,因此当他调用 ShowDialog 方法时,它会根据映射决定加载哪个 UI。 CodeProject: Showing Dialogs When Using the MVVM Pattern

【问题讨论】:

我添加了您的第一张图片,但您的第二张图片似乎相同 - 您要查看吗? 谢谢,是的,出了点问题。我替换了第二个链接,所以它现在应该指向正确的图片。 最好和最简单的方法之一是使用依赖注入容器(如 Unity)并仅通过接口引用事物。因此,您的视图将有一个名为 IViewModel ViewModel get;set; 的属性,它会通过解析来自 DI 容器的接口来填充该属性。 好的,我去看看,谢谢! 谁说你的视图不能知道你的虚拟机?这没有任何意义,因为它必须绑定虚拟机的属性。 【参考方案1】:

如果您在 View 和 ViewModel 之间没有一个引用,那么为什么您的 ViewModels 项目会尝试引用 Views 项目?

您的图片暗示这是为了允许显示对话框。在这种情况下,您通常会在 ViewModels 项目中定义一个接口,该接口具有方法 ShowDialog(object viewModel) - 称之为 IDialogService 或其他名称。

然后您将拥有第 4 个 bootstrapper 项目,该项目将负责启动应用程序、显示主窗口并实现此IDialogService,将 ViewModel 映射到 View 并显示它。

【讨论】:

确切地说,显示对话框和其他视图.. 听起来就像我正在寻找的一样,并且使用 IDialogService 关键字我找到了一些示例项目。谢谢! PS:对不起,我不能赞成你的回答,其他行动也不能证明这是有用的。又是因为缺少声望点...【参考方案2】:

VM 知道 View 更值得怀疑,您可能应该避免它。您可能希望在 View 项目中实现对话框功能。仅仅因为它的逻辑并不意味着虚拟机应该负责它。如果你的视图模型命令式地执行像ShowDialog() 这样的方法,那么你应该重构VM 并将ShowDialog() 方法调用拉到视图库中。如果您必须使用 VM 触发它,请在 ViewModel 上定义方法委托以使其触发,但将 ShowDialog() 分配给 View 层中的该委托。

【讨论】:

在我现在实现的版本中,有这个服务知道哪个视图模型属于哪个视图。因此,当另一个(主)项目启动应用程序并创建 VM 时,它会在构造函数中传递服务接口。现在,VM 可以在不了解视图的情况下调用显示对话框函数。服务根据传递的视图模型决定它必须显示哪个视图。 @HansVader 听起来您已经决定了一种模式,但我想说的是,您可能在组织和代码维护方面遇到困难。让 ViewModel 调用名为 ShowDialog() 的方法是您的 GUI 与 ViewModel 的隐式耦合,因为您的 ViewModel 理解对话框的概念,它实际上应该仅限于 View。我认为最好在 ViewModel 上设置一个 ViewModel 触发的事件,但 View 会将 ShowDialog() 方法调用分配给该事件。这是一个小提琴:dotnetfiddle.net/dCMumi 是的,我在创建登录掩码时已经遇到过这样的问题。因为我想切换到注册用户界面,但虚拟机不应该知道它只是一个用户控件还是一个对话框......我可能会用事件来实现你的建议。谢谢! 但是你如何管理视图呢?导致视图触发命令,例如在视图模型中定义的“ShowHelpDialog”。那么如何避免 VM 知道它是 Dialog/UI 呢? @HansVader 可能只是命令名称的问题。与其根据 UI 来命名命令,不如根据 VM 中发生的事情来命名。在我的小提琴中,这是一个名为AfterDataFetched 的事件。即使最终结果是相同的,即在获取数据后显示对话框,VM 除了在获取数据后触发AfterDataFetched 事件外什么都不知道。 View 负责定义事件中发生的情况,从而实现清晰的分离。而且,您现在可以使用该命令做的不仅仅是对话内容。

以上是关于MVVM:GUI 和 ViewModel 之间的真正分离的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI - MVVM之ViewModel

MVVM 架构,ViewModel和LiveData

MVVM和MVC之间的差别

Android - MVVM 中 ViewModel 状态的最佳实践?

什么是mvvm?

使用 TabControl (MVVM) 显示不同的 ViewModel