11

我对 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。但这是处理问题的好方法吗?

4

2 回答 2

16

实际上,执行此操作的正确方法是当您第一次创建 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 属性。然而,MV-VM 纯粹主义者会说永远不要这样做,说 UI 永远不应该知道模型,因为如果模型改变,你必须改变 UI。我的论点是,如果模型发生变化,出于完全相同的原因,您无论如何都必须更改 ViewModel。唯一的节省是如果有多个视图都共享相同的 ViewModel,因为您只需要在一个地方更改它,但实际上,像“名称”这样的东西不会将它的“名称”从模型更改为ViewModel 所以在这些情况下,无论如何它都是非论点。

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

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

高温下,

标记

于 2011-05-21T02:51:09.377 回答
1

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

于 2009-05-13T07:03:53.183 回答