MVVM模式下如何在视图模型之间传递数值

8
我试图处理从一个ViewModel传递值到另一个ViewModel的问题。以下是一个例子。
我们有父视图及其相应的ViewModel,在该视图中,我们选择项目,然后想创建新的子视图(以编辑所选内容的详细信息),并在XAML中实例化其ViewModel。 当我需要将值传递给子ViewModel构造函数时(它是必须从数据库中获取的数据的Id),问题就出现了。我假设父ViewModel必须与子ViewModel通信 - 但是由于子ViewModel不会在XAML之前被实例化,因此无法完成。因此,我们无法使用Messenger(MVVM Light Toolkit)仅从父ModelView传播该信息,因为子ModelView尚未能够订阅(注册该类型的消息)。
我不想打破MVVM模式,并且找不到任何好的解决方案。我感激您提供的所有帮助。

你是否在使用视图模型定位器?你提到你的VM直到子视图存在才被实例化。你是在代码后台设置数据上下文吗?我们的父VM拥有一个子VM集合。我们使用与MVVM Light非常相似的信使。 - SQLMason
2
哦,你不会“破坏”MVVM,它只是一种指导而不是一种信仰。 - SQLMason
不,我不知道视图模型定位器 - 我会去查一下。Child的DataContext为其viewModel在XAML中设置。在我们的解决方案中,Parent不能拥有Children的VM集合,它只能传递要从数据库中获取的数据的ID到Child的VM中。 - kkris1983
使用ViewModel Locator,这正是你所需要的。在最简单的形式中,它是一个静态的MainViewModel,它在APP.XAML代码后台实例化。这样做将允许你使用VS中对象的属性正确地绑定到你的元素。MainViewModel具有所有其他视图模型/模型集合。例如:Locator.Main.Parent.Child。 - SQLMason
Dan Andrews,感谢您的评论,我现在会去检查那个定位器。最好的问候。 - kkris1983
2个回答

6
MVVM模式的主要原则之一是,您应该能够在没有视图的情况下执行ViewModel代码,以便单元测试您的视图逻辑。换句话说,理想情况下,您应该能够在“无头”模式下执行应用程序。
在您的示例中,您指出ParentView创建了ChildView,然后创建了一个ChildViewModel(您正在努力连接它)。这在无头模式下能够工作吗?看起来您依赖于您的View来执行这种父子导航。
如果您将它反过来,即让ParentViewModel创建ChildViewModel,则不再存在ViewModel之间的通信问题。ParentView需要“监视”(即属性更改)新创建的ChildViewModel,并相应地构造ChildView。
更详细地说:
  1. ParentView实例化ParentVM
  2. 用户以某种方式进行交互,需要显示子项
  3. ParentVM通过一个ChildVM属性创建ChildVM
  4. ParentView处理由此产生的PropertyChanged事件,创建ChildView,并将其DataContext设置为ChildVM。

无论我在书籍中查看MVVM模式,VM都是在View中实例化的,例如资源。也许有些地方我没有理解,请您指正一下吗? - kkris1983
3
在MVVM架构中,有一个“黄金法则”,即VM视图模型不知道View视图的存在。如果违反这个规则,就无法在没有View的情况下运行VM。我的建议是:(1) ParentView实例化ParentVM,(2) 当需要显示子视图时,用户进行交互操作,(3) ParentVM创建ChildVM并通过ChildVM属性将其暴露出来,(4) ParentView处理结果的PropertyChanged事件,创建ChildView并将其DataContext设置为ChildVM。这样可以解决您的问题!同时,这也是MVVM框架下完全合理的用法。 - ColinE
1
@ColinE 我不会那样做。在我看来,应该先创建视图模型。最好完全将视图模型与视图分离,并使用某种发现机制来查找视图模型的正确视图。 - James L
2
我更喜欢保持简单。这个问题来自一个在MVVM方面挣扎的人,我认为添加IOC或DI不会有太大帮助。我已经创建了许多MVVM应用程序,其中顶层视图创建了顶层视图模型,但仍能够对视图模型进行单元测试并具有设计时数据。当然,让某些第三方实体耦合视图和视图模型是可以的。但这不是必要的,也不是MVVM本身的一部分。 - ColinE
@Colin E,您能否指出一个链接,可以解释如何完成您所述的第四点? - KhannaB7
显示剩余2条评论

0

你现在使用的是什么框架?我指的是MvvmLight、Caliburn Micro或Prism。每个框架都有一个消息基础架构。您可以利用它们使用发布/订阅方法来传递状态。例如,请看一下Prism。有几个快速入门演示了事件模型。您还可以维护一个视图控制器以编排视图之间的通信。

看一下Ward Bell的Prism Explorer示例应用程序。这是一个'09年的article,但今天仍然相关。特别是请看他如何将实体对象从列表视图传递到子详细视图。


我使用MvvmLight,并且对消息传递很熟悉,但问题在于父级VM无法发送消息,因为子级VM可能尚未实例化,因此无法注册该消息。 - kkris1983
虽然我不熟悉你的架构,但你可以有一个控制器订阅事件,然后缓存结果。稍后使用它来实例化视图,并将其传递给状态缓存中的新视图。 - davidbitton

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