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 之间的真正分离的主要内容,如果未能解决你的问题,请参考以下文章