父视图和子视图模型之间通过notifychanged或命令属性进行通信?

时间:2016-06-30 09:49:08

标签: c# wpf mvvm

在我的WPF应用程序中,我遵循MMV模式。 我有一个嵌套子视图的主视图。我有一个主VM来保存子VM的实例。在某些时候,当VM VM的某些属性发生变化时,需要通知主VM。

我在网上搜索了很多。首选方法似乎是使用现有框架(MVVMlight / Prism)和/或某种信使服务。每当在任何板/常见问题上询问有关VM交互的问题时,您可以确定至少有一个答案建议使用此方法。 虽然我可以很好地看到它在大型应用程序中的优势(或者如果您正在寻找“通用”解决方案),但对于小型应用程序来说,它有时似乎是一个很大的开销。

对我来说,最明显的方法,特别是在小型应用程序中,将是

  • 订阅子VM的NotifyPropertyChanged。

OR

  • 让主VM将(Relay)命令传递给子VM,以便子VM可以在某个属性发生更改时执行命令(甚至可以将更改后的值作为命令参数传递),这样主VM就知道了关于变化,可以处理它。

我想知道这两种方法是否存在“错误”,因为我看不到它们违反了MVVM规则?也许我错过了什么?

当您无法利用在应用程序中使用基于信使的方法的优势时,可以使用其中一种方法吗?

3 个答案:

答案 0 :(得分:3)

我们使用一种简单的方法。创建此子视图模型时,只需将Action或Func传递给构造函数即可。然后,只要您需要更新父视图模型,就可以调用该操作。

实施例

public class ParentViewModel
{
    public ParentViewModel()
    {
        childViewModel = new ChildViewModel(MyAction);
    }

    private void MyAction()
    {
        //i was called by childview model, now do something
    }

    ChildViewModel childViewModel;
}

public class ChildViewModel
{
    private readonly Action action;

    public ChildViewModel(Action action)
    {
        this.action = action;
    }

    private int myVar;

    public int MyProperty
    {
        get { return myVar; }
        set
        {
            myVar = value;
            if (something)
            {
                //call the parent viewmodel
                action.Invoke();
            }
        }
    }
}

答案 1 :(得分:2)

第一种方法的问题是主VM必须知道子VM属性,所以你有点紧密地将这两者绑在一起。在使用某种消息传递系统时,您只能将数据传递给“父母”。并且没有关于其子对象内部的信息。

第二种方法的问题是可测试性 - 如果您正在为您的虚拟机编写测试,您必须模拟那些(中继)命令,以便您进行测试(或者在内部进行一些空检查)调用它的方法,brrr ...)即使它意味着只传递无效的哑空对象。此外,通常使用消息传递组件更好,因为它在所有应用程序中统一 - 您不必担心如何在VM之间进行通信,因为您在任何地方以相同的方式执行此操作:)。

作为附注 - 可能如果你的应用程序很小(只有主 - 孩子vms),你可以选择你提到的任何方法。然而,即使在小型应用程序中,我也关心模式/实践,因为实现它们非常简单。例如(可能是自定义的?)消息传递组件的实施工作并不比您为实现其他任何工作所需的努力更大:)。 希望这有用:)

答案 2 :(得分:0)

查看将子视图模型中所做更改传递给其父视图模型的选项。对于小型应用程序,您完全没有必要使用消息总线,事件聚合器。

  1. 订阅子视图模型发出的INotifyPropertyChanged事件的父级没有任何问题。当然你让父母依赖孩子,但如果你不需要松散地耦合这些组件,那就没关系。

  2. 不建议将命令从父级传递给子级,因为如果父级也需要在子级上调用命令,则可能会设置依赖关系周期。

  3. 如果您的应用程序非常小,另一个选择是只有一个视图模型。一个或多个视图共享一个datacontext没关系。