【问题标题】:Pass or Get a value from Parent ViewModel down to Sub-ViewModel?将父视图模型中的值传递或获取到子视图模型?
【发布时间】:2011-02-01 20:09:25
【问题描述】:

我正在使用 MVVM Light 框架以及 Unity for DI。我有一些嵌套视图,每个都绑定到相应的 ViewModel。 ViewModel 通过 Laurent Bugnion 放入 MVVM Light 的 ViewModelLocator 想法绑定到每个 View 的根控件 DataContext。这允许通过静态资源查找 ViewModel,并通过依赖注入框架(在本例中为 Unity)控制 ViewModel 的生命周期。它还允许 Expression Blend 查看与 ViewModel 相关的所有内容以及如何绑定它们。

正如我所说的,视图有一个健康的嵌套剂量,但视图模型并不真正了解彼此。父视图通过静态资源 ViewModelLocator 绑定到其对应的 ViewModel(它使用 Unity 来控制 ViewModel 对象的构造和生命周期)。该父视图包含一个用户控件,它是另一个子视图,然后它也会通过 ViewModelLocator 获取其对应的 ViewModel。 ViewModel 之间没有相互引用,也不知道彼此之间的任何层次结构。

下面是一个 ViewModel 如何通过消息传递进行交互的示例。我有一个父视图,它有一个 ComboBox 数据绑定到其 ViewModel 中的 ObservableCollection。 ComboBox 的 SelectedItem 也绑定(双向)到 ViewModel 上的属性。当 ComboBox 的选择发生变化时,这是为了触发其他 View 和子 View 中的更新。目前,我正在通过 MVVM Light 中的消息系统完成此操作。

所以我想知道从一个 ViewModel 到另一个 ViewModel 获取信息的最佳做法是什么?在这种情况下,我需要传递给子 ViewModels 的基本上是代表当前登录用户的用户 Guid。最顶层的父视图(好吧,ViewModel)会知道这些信息,但我不知道如何将它放到子视图模型中。

我能想到的一些可能的方法:

  • 子 ViewModel 是否应该询问 静态资源 ViewModelLocator 用于 对同一对象的引用 父视图正在使用和访问 财产那样?这好像是 ViewModels 通过彼此的 物业不是很干净而且 将它们不必要地耦合在一起。

  • 我已经在使用消息来通知 用户选择的子视图 组合框中的新项目并 相应地更新。但对象 正在选择的类型 ComboBox 并不是真的直接 与该数据值相关的 子视图需要。

【问题讨论】:

  • 实际上,经过身份验证的用户 ID 并不是我需要从最顶层的 ViewModel 获得的唯一值;还有一个来自 DatePicker 控件的开始和结束日期值,需要向下传递子 ViewModel 以过滤一些数据。

标签: xaml mvvm nested viewmodel mvvm-light


【解决方案1】:

我基本上已经看到了两种方法。对于一般的跨 VM 通信,事件聚合器模式效果很好。

但是对于 VM 的层次结构,使用访问者模式可能会更好。通过访问者,您可以获得流经层次结构的信息,例如自动为每个孩子提供对父 VM 的引用。

您也可以使用 EA 执行此操作,但挑战在于在消息的有效负载中传递足够的信息,以便孩子们知道这是他们应该关心的事情。

就虚拟机定位器而言,绝对不是! VM 定位器的内容严格用于在 UI 中绑定,它不应在该上下文之外出现(最好)。

我的 $.02 格伦

【讨论】:

  • 一般来说很好的答案,其中一部分接近我选择的解决方案。我没有虚拟机层次结构,只有视图是嵌套的,然后补充虚拟机是绑定到每个视图的数据。我想我最终得到了 EA 之类的东西;我会发布一个答案来解释我做了什么。
【解决方案2】:

我决定让子 ViewModel 发布一条请求所需信息的消息,然后让父 VM 订阅该消息类型和密钥令牌。我不想过度使用这种通信方式,但我认为它对于一些我无法找到通过视图层次结构向下推的方法的数据将是有效的。到目前为止,大部分数据传递都是为了响应事件,但并不是每条数据都可以通过这种方式传递,尤其是在获取数据或事件发生在新视图之前的不同屏幕上时甚至被构造和读取以接收数据。

我确实与这个领域的一些知名人士(Glenn Block、John Papa 和 Rob Eisenberg)在 Twitter 上进行了对话。他们提出了许多类似访问者模式的建议,但我不确定如果没有 VM 的层次结构,它是否能很好地工作。这可能是因为我的设计几乎是 View-first,而不是 ViewModel-first 方法。另一个可能可行的建议是修改我的 ViewModelLocator 和依赖注入使用,以包括在创建时将数据值传递给子 VM 的能力。由于 VML 的静态特性,我在设想它时遇到了一点麻烦,并决定我想出的消息请求解决方案暂时更直接和简单。如果最终有太多数据落入这种情况,我可能不得不重新考虑解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-05
    • 1970-01-01
    • 2013-05-11
    • 1970-01-01
    • 2017-05-04
    相关资源
    最近更新 更多