【问题标题】:How to present a Collection of (View)Models in a ViewModel如何在 ViewModel 中呈现(视图)模型的集合
【发布时间】:2010-10-24 17:57:33
【问题描述】:

我有一个关于 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 对象。我也不认为复制子对象是一个好主意,因为它会导致冗余,并且在我的应用程序上下文中,也不需要/不可能创建新的子对象。

我也想过下面的类设计:

class ParentVM {
    Parent _parent;

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

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

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

【问题讨论】:

    标签: wpf collections mvvm viewmodel


    【解决方案1】:

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

    【讨论】:

    • 嗨 Torsten (@Torsten),我完全承认这是有偏见的,但是由于您使用我在回答中已经解决的问题将自己的答案标记为已接受的答案,并提供了原因也就是说,介意改变它以便我接受吗?无论如何,你不能给自己加分,正如你所看到的,其他人确实很欣赏我在这里解释为什么可以从 ViewModel 中公开模型的文章。谢谢!
    • @MarqueIV 我认为我将我的答案标记为解决方案,因为您的分析器比我的更晚。我也看到我自己赞成你的答案,所以你去吧。
    • 谢谢!非常感激! :)
    【解决方案2】:

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

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

    这样你就有了一个带有 Parent->Children->Child 的模型和一个 ParentVM->ChildVMs->ChildVM 的 ViewModel,我相信这正是你想要的。

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

    另外,以“纯粹”方式执行它会产生性能开销,因为您不能像上面的 Name 那样简单地委托给模型项,因为视图永远不会知道任何模型 -生成对 Name 属性的更改,除非您还在 VM 中添加所有额外的更改通知,这意味着您现在在模型中有一个更改通知,其唯一目的是在 VM 中触发 second 更改通知然后通知 UI。纯的?是的。性能侵入?您敢打赌,尤其是在进行大量更改并且您正在使用 INotifyPropertyChanged 接口时,因为这意味着您必须在更改处理程序中进行字符串比较以检测和委托所有这些更改!但是,如果您直接绑定到 ParentVM.Parent.Name 属性,您将已经收到来自模型的更改通知来通知 UI,并且您还可以让您的虚拟机保持干净,以处理仅特定于虚拟机或视图的内容。

    然而,我从来没有在模型中放置任何仅供查看的信息。这对我来说就是 ViewModel 的用途。例如,如果孩子们有一个基于枚举或其他什么的特定颜色,那对我来说是 ChildVM 中的东西,而不是模型本身,如果模型中有任何属性决定该颜色,比如该枚举的属性,在这种情况下,是的,我会从 ChildVM 内部的模型中连接更改通知。 (说实话,我什至可以直接通过 UI 中的颜色转换器来实现,仍然绑定到模型的枚举。这真的是一个个案。)

    HTH,

    标记

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多