如何在ViewModel中呈现(视图)模型的集合

时间:2009-05-08 09:12:51

标签: wpf collections mvvm viewmodel

我对C#/ WPF的MVVM设计有疑问。我看过几个演示应用程序,但它们并没有真正解决我的问题。 我的应用程序由包含其他对象的对象组成。就像父子关系一样。

我现在的问题是:

  • children属性必须是ViewModel
  • 如果是这样,我如何通过ViewModels创建包含现有子对象的新父对象?

我有以下情况:

class Child {
    string Name;
}

class ChildVM {
    Child _child;
    string Name{return _child.Name;}
}

class Parent {
    string Name;
    List<Child> children;
}

class ParentVM{
    Parent _parent;

    string Name{return _parent.Name;}
    List<ChildVM> children {get;set;}

    ParentVM(Parent p){_parent = p;}
}

void CreateANewParent(){
    List<ChildVM> children = new List<ChildVM>(){new ChildVM(new Child()),...};
    ParentVM parent = new ParentVM(new Parent());
    foreach(ChildVM child in children)
        parent.children.Add(child);
}

这里的问题是,ParentVM包含ChildVM,但实际的Parent(在ParentVM内)没有ChildVM对象包含的Child对象。我也认为复制Child对象不是一个好主意,因为它会导致冗余,在我的应用程序上下文中也没有必要/可能创建新的Child对象。

我还考虑过以下课程设计:

class ParentVM {
    Parent _parent;

    string Name{return _parent.Name;}
    List<Child> children {get{return _parent.Children;}}
}

但是,这意味着如果我想操作ParentVM的Child对象,我会直接操作Model。

另一方面,我可以简单地将(Model)Parent留空,并使用ParentVM在数据库中创建一个新的Parent。但这是处理问题的好方法吗?

2 个答案:

答案 0 :(得分:15)

实际上,执行此操作的正确方法是在首次创建ParentVM时,遍历传入的Parent的子节点,为每个子节点创建一个ChildVM,然后将这些ChildVM对象添加到ParentVM的ChildVMs属性中。 (有些人会把这个属性称为'儿童',但我个人喜欢明确它是ChildVMs的集合,而不是Child对象的集合。只需添加'VM'后缀就可以非常清楚。

然后您还必须收听实际Parent's Children集合的更改通知,并相应地更新您的ChildVMs集合。

这样你就拥有了一个带有Parent-&gt; Children-&gt; Child的模型和一个ParentVM的ViewModel-&gt; ChildVMs-&gt; ChildVM,我完全相信你的想法。

现在我也相信你应该能够直接从ParentVM公开Parent以及直接从ChildVM公开Child,因为你的UI可能绑定到这些项目的各种属性,例如你的名字上面的财产。然而,M-V-VM纯粹主义者会说永远不会这样说UI永远不会知道模型,因为如果模型发生变化,你必须改变UI。我的论点是,如果模型发生变化,你必须以完全相同的理由改变ViewModel。唯一的节省是如果有几个视图都共享相同的ViewModel,因为你只需要在一个地方更改它,但实际上,像'Name'这样的东西不会改变它从模型到它的“名称” ViewModel所以在这些情况下它仍然是一个非参数。

另外,以“纯粹主义”的方式进行性能开销,因为你不能简单地委托模型项,就像你在上面使用Name一样,因为视图不会知道任何模型 - 生成对Name属性的更改,除非您还在VM中添加了所有额外更改通知,这意味着您现在在模型中有一个更改通知,其唯一目的是在VM中触发第二个更改通知然后通知用户界面。纯?是。业绩创?您打赌,特别是在进行大量更改并且您正在使用INotifyPropertyChanged接口时,因为这意味着您必须在更改处理程序中进行字符串比较以检测并委派所有这些更改!但是,如果您直接绑定到ParentVM.Parent.Name属性,则您已经从模型中获得了更改通知以通知UI,并且您还可以保持VM清洁以查找仅特定于VM或视图的内容。

然而,我从未做过的是在模型中放置任何仅查看信息的内容。对我来说就是ViewModel的用途。因此,例如,如果孩子们有一个基于枚举或其他的特定颜色,那对我来说就是ChildVM而不是模型本身,如果模型中有任何属性决定颜色,就像枚举的属性,在这种情况下,是的,我会在ChildVM内部连接模型的更改通知。 (说实话,我甚至可以通过UI中的颜色转换器直接进行,仍然绑定到模型的枚举。这实际上是一个案例的事情。)

HTH,

标记

答案 1 :(得分:1)

好的,我从.NET论坛得到了一些帮助和建议: 我将通过在ViewModel内部为模型提供Get-Method来解决问题。因此,如果我使用现有的ChildVM创建一个新的Parent,我只需在ChildVMs中返回Child引用并将它们分配给我的新Parent。