【问题标题】:Using Commands declared in "Parent" ViewModel (MVVM)使用在“父”视图模型 (MVVM) 中声明的命令
【发布时间】:2011-12-30 16:12:59
【问题描述】:

(注意:我选择不使用导航框架)

我有一个与 WizardView 链接的 WizardViewModel。
WizardViewModel 声明并实例化一个命令“Next”。
它还包含一个 SpellViewModel 类型的属性“ActiveSpell”。

SpellViewModel 包含多个 PageViewModel,每个都有对应的 View。
ActivePage 属性(在 SpellViewModel 上)告诉 ui 采用哪个视图。

现在我有以下问题:
当我点击一个按钮切换到下一页时,
我需要访问 WizardViewModel 中定义的“下一步”命令,
但我只能访问那里的 PageViewModel。

我可以为每个子 ViewModel 添加一个 Parent 属性,
但我不确定这是否是个好主意。
或者也许还有另一种更好/更常见的方法来做到这一点。

【问题讨论】:

  • 听起来您可能需要将命令分离到自己的类中
  • 本质上并没有错,在 MVVM 中让子 ViewModel 了解他们的父母。实际上,您可以在子 ViewModel 的构造函数中使用依赖注入,并且 要求 让子 ViewModel 了解父级。另一种处理方法是让父 ViewModel 订阅子级引发的事件。但是,正如我在回答中指出的那样,您会发现在大型应用程序中使用事件聚合器会更容易,就像 Sailor 所描述的那样。

标签: c# wpf mvvm command


【解决方案1】:

您可以使用Event Aggregator,调整ViewModels之间的交互。

【讨论】:

  • EventAggregator 用于解耦视图模型或模块。提供的视图模型结构是耦合的,因此,没有理由使用 EventAggregator 或其他消息聚合器。
  • 正如您在评论中提到的那样,作者想要实现一个向导树。所以在这样的设计中使用 EventAggregator 似乎是一个很好的解决方案。
【解决方案2】:

您不需要 Parent 属性。您的视图模型结构很好,只需看一下图片,即可了解您应该如何将视图模型绑定到视图:

下一个命令应该是这样实现的:

public void NextExecute()
{
    ActualSpell.MoveToNextPage();
}

更新: 根据你的评论,Arokh,我已经更新了这篇文章。 我认为,在这种情况下,您应该在 WizardViewModel 中实现 ActivateCreatePersonSpell 命令。该命令应该:

  • 保存实际拼写状态
  • 打开 CreatePerson 法术
  • 一旦人被创建,将保存的咒语与创建人的结果一起设置

您需要做的最后一个是将ActivateCreatePersonSpell 命令绑定到页面上的按钮。我建议将 ViewModelLocator 用于这些目的。例如,查看this 帖子。

【讨论】:

  • 这也是一个很好的可视化。如果要执行 Next 的控件是父视图(而不是子视图)的一部分,则子 ViewModel 可能不需要访问 Next Command。
  • 这实际上是我目前为下一个/上一个按钮做的方式。但我想建立一个像向导一样的树,而不仅仅是一个线性的。例如,“Spell”可能会引导用户创建房屋,一旦用户必须指定房屋的所有者,用户可以单击活动页面上的按钮,该按钮打开 CreatePerson Spell,一旦 Person 是创建了 CreateHouse Spell 简历。为此,我创建了 Enter/Leave 命令。但由于这些命令在 WizardViewModel 上,我无权访问它们。
  • 我接受了你的回答,因为我可以想象我将如何从那里开始。但是我选择了“Wizard”属性,因为我认为后面引入的问题比使用 ViewModelLocator 引入的复杂性要小,因为我的应用程序不会很大。如果情况发生变化,我一定会再看一遍。
【解决方案3】:

我必须实现一次向导,我喜欢并模仿了 Josh Smith 和 Karl Shifflett 在此示例项目中设置他们的 WizardViewModel 和向导页面视图模型的方式(文章中提供了源代码):

http://www.codeproject.com/KB/WPF/InternationalizedWizard.aspx

他们保留 Next 命令作为其 WizardViewModel 的一部分,但创建了一个 WizardPageViewModelBase,所有向导页面都从该基础派生。这允许 WizardViewModel 控制哪个页面是当前页面,它允许 WizardViewModel 查询当前页面视图模型以查看 Next 命令是否可以执行,从而启用或禁用向导上的 Next 按钮。 (也就是说,向导视图模型知道页面视图模型,但页面视图模型不需要知道“父”向导视图模型的任何信息。)

至于添加到父视图模型的链接,这是一种行之有效的方法,我之前开始使用 MVVM 时已经这样做了,但后来我发现这种方法会导致每个视图都难以维护代码模型变得相互依赖。

【讨论】:

  • 是的,我的实施也基于该项目。它对我帮助很大,但由于我想要一个像向导而不是线性的树,我需要从 PageView 访问 WizardViewModel 的命令(至少这是目前我能想到的唯一方法)。有关详细信息,请参阅我对 Vladimir Dorokhov 答案的评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-29
  • 1970-01-01
  • 2010-11-28
  • 1970-01-01
  • 2013-10-12
  • 2022-01-09
相关资源
最近更新 更多