【问题标题】:MVVM: How to handle interaction between nested ViewModels?MVVM:如何处理嵌套 ViewModel 之间的交互?
【发布时间】:2011-02-04 07:32:21
【问题描述】:

我一直在尝试经常提到的 MVVM 模式,并且在某些情况下我很难定义清晰的边界。在我的应用程序中,我有一个对话框,允许我创建与控制器的连接。对话框有一个 ViewModel 类,很简单。但是,该对话框还包含一个附加控件(由ContentTemplateSelector 选择),这取决于所连接的控制器的特定类型。该控件有自己的 ViewModel。

我遇到的问题是,当我按 OK 关闭对话框时,我需要实际创建请求的连接,这需要在内部特定于 Controller 的 ViewModel 类中捕获信息。简单地让所有特定于 Controller 的 ViewModel 类实现一个构造连接的通用接口是很诱人的,但是内部 ViewModel 真的应该负责这个构造吗?

我的一般问题是:对于 ViewModel 应该如何相互交互,是否有任何普遍接受的设计模式,尤其是当“父”VM 需要“子”VM 的帮助才能知道该做什么时?


编辑:

我确实提出了一个比我最初想的更简洁的设计,但我仍然不确定这是否是“正确”的做法。我有一些后端服务允许 ContentTemplateSelector 查看 Controller 实例并伪神奇地找到要为连接构建器显示的控件。让我烦恼的是,我的顶级 ViewModel 必须查看生成的控件的 DataContext 并将其转换为适当的界面,这似乎是个坏主意(为什么 View 的 DataContext 有任何东西与创建连接有关吗?)

我最终得到了这样的东西(简化):

public interface IController
{
    IControllerConnectionBuilder CreateConnectionBuilder();
}

public interface IControllerConnectionBuilder
{
    ControllerConnection BuildConnection();
}

我有我的内部 ViewModel 类实现 IControllerConnectionBuilder 并且控制器返回内部 ViewModel。然后顶层 ViewModel 将这个IControllerConnectionBuilder 可视化(通过伪魔法机制)。它仍然让我有点困扰,它是我的内部 ViewModel 执行构建,但至少现在我的顶级 ViewModel 不必知道肮脏的细节(它甚至不知道或关心可视化控件正在使用视图模型)。

如果有办法进一步清理这个问题,我欢迎提出其他想法。我仍然不清楚 ViewModel 应该承担多少责任。

【问题讨论】:

  • 我们在工作中经常问自己这类问题。你这个问题的措辞很好,所以我希望你能在这里得到一些好的反馈。
  • 谢天谢地,这是一个宠物项目,所以我有幸探索不同的设计。我的商店没有采用 WPF 或 MVVM,因为早期阶段的开销和笨拙对于我们当前的日程安排是不可接受的。我坚信这是一项技术,一旦我们了解如何使用它,它就会在生产力方面带来巨大的收益,但它的视角发生了如此大的转变,以至于很难知道在设计中应该在哪里划清界限。

标签: c# architecture mvvm


【解决方案1】:

我最近尝试使用 Unity(Microsoft 企业库)来使用依赖注入。当使用完全定义两个视图模型彼此不需要的接口时,这可能是一条要走的路。我知道 MEF 将是依赖注入的另一种选择。

HTH

【讨论】:

  • 谢谢,我实际上在这个应用程序中使用了 MEF,它在允许 UI 的非常丰富的可扩展性方面有很大帮助。正是这种可扩展性给设计带来了挑战,因为现在 UI 托管的控件实际上几乎一无所知。实际上,我想出了一种更简洁的方法来做到这一点,我今天回家后会详细说明。
【解决方案2】:

一个适用于视图模型之间交互的选项是直接绑定到位于视图模型类之间的observer 类。

【讨论】:

  • 感谢您的链接;实际上,我通过共享一个由我的 MainViewModel 实现的 IMainViewModel 服务,使用与此类似的模式进行其他协调。我认为进一步重构它可能是有意义的,这样“共享”功能就不会绑定在主窗口的模型中,而是一个 MainObserver。
  • 这是一个有用的方法。我的设计仍然有点精神分裂,但我开始了解虚拟机如何通过使用共享服务进行通信。感觉有点颠倒了,因为我已经习惯了一个“父母”知道它的“孩子”的一切。现在更多的是我的班级说“我需要完成这件事”以及我对加强和照顾它几乎一无所知的应用程序的某些部分。
【解决方案3】:

我认为您想让您的顶级ViewModel 知道NestedViewModel 的存在,从分层的角度来看这是有道理的,主视图包含子视图。

在我看来,您的直觉是正确的,嵌套的 ViewModel 暴露由顶层用户操作发起的行为是不正确的。相反,顶级ViewModel 应该为其关联的视图提供行为。

但我会考虑将连接构建的责任转移到ICommand,并通过您的顶级ViewModel 公开此命令。然后,您将主对话框上的 OK 按钮绑定到此命令,该命令将仅委托给顶级 ViewModel,例如,在执行时调用 ViewModel.CreateConnection()

然后,您的嵌套控件的责任纯粹是收集数据并将其公开给其NestedViewModel,以供包含ViewModel 使用,理论上它在需要相同信息的不同上下文中更可重用输入(如果有) - 假设您想重新使用它来编辑已创建的连接。

如果不同类型的NestedViewModel 暴露了一组完全不同的数据,唯一的问题就是。

例如,一个公开 HostNamePort 作为属性,另一个公开 UserNamePassword

在这种情况下,您可能需要做一些基础设施工作才能让您的顶级 ViewModel.CreateConnection() 仍然以干净的方式工作。虽然如果您有少量嵌套控件类型,可能不值得付出努力,简单的NestedViewModel 类型检查和强制转换可能就足够了。

这听起来可行吗?

【讨论】:

  • 这里的挑战是外部 ViewModel 在编译时实际上并不知道其 InnerViewModel 的类型。控制器在运行时作为应用程序的扩展引入,在底层进行一些类型发现,以通过自定义 DataTemplateSelector 连接特定的嵌套控件。我知道 DataContext 将隐含地成为特定的嵌套 ViewModel,但检查 DataContext 并尝试将其转换为共享接口对我来说感觉很糟糕。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 2018-12-27
  • 2018-11-21
  • 1970-01-01
  • 1970-01-01
  • 2011-09-05
相关资源
最近更新 更多