我有一个关于 C#/WPF 的 MVVM 设计的问题。我看过几个演示应用程序,但它们并没有真正解决我的问题。 我的应用程序由包含其他对象的对象组成。很像父母与孩子的关系。
我现在的问题是:
我有类似以下场景:
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 对象,我将直接对模型进行操作。
另一方面,我可以简单地将(模型)父级留空并使用 ParentVM 在数据库中创建新的父级。但这是解决问题的好方法吗?
实际上,执行此操作的正确方法是,当您首次创建 ParentVM 时,迭代传入 ParentVM 的子级,为每个子级创建一个 ChildVM,然后将这些 ChildVM 对象添加到 ParentVM 的 ChildVMs 属性中。 (有些人会将该属性称为“Children”,但我个人喜欢明确它是 ChildVM 的集合,而不是 Child 对象的集合。只需添加“VM”后缀即可非常清楚。
然后,您还必须监听实际 Parent's Children 集合的更改通知,并相应地更新您的 ChildVMs 集合。
这样你就有了一个包含 Parent->Children->Child 的模型和一个 ParentVM->ChildVMs->ChildVM 的 ViewModel,我相信这正是你想要的。
现在我也相信您应该能够直接从 ParentVM 公开 ParentVM 以及直接从 ChildVM 暴露 Child,因为您的 UI 可能绑定到这些项目上的各种属性,例如上面的 Name 属性。 然而,M-V-VM 纯粹主义者会说永远不要这样做,他们说 UI 永远不应该知道模型,因为如果模型发生变化,你就必须更改 UI。 我的观点是,如果模型发生变化,出于完全相同的原因,您无论如何都必须更改 ViewModel。 唯一的节省是,如果有多个视图都共享同一个 ViewModel,因为您只需在一处更改它,但实际上,像“名称”这样的内容不会将其“名称”从模型更改为ViewModel 所以在这些情况下它无论如何都是无争议的。
另外,以“纯粹”的方式进行操作会带来性能开销,因为您不能像上面的名称那样简单地委托给模型项,因为视图永远不会知道任何模型生成的更改到 Name 属性,除非您还在虚拟机内添加了所有额外的更改通知,这意味着您现在在模型中拥有一个更改通知,其唯一目的是在虚拟机中触发“第二个”更改通知,然后通知 UI。 纯的? 是的。 性能侵入? 您敢打赌,尤其是当发生大量更改并且您正在使用 INotifyPropertyChanged 接口时,因为这意味着您必须在更改处理程序中进行字符串比较来检测和委托所有这些更改! 但是,如果您直接绑定到 ParentVM.Parent.Name 属性,您将已经收到来自模型的更改通知以通知 UI,并且您还可以保持 VM 干净,以处理仅特定于 VM 或视图的内容。 但是我从来没有在模型中放置任何仅供查看信息的内容。对我来说,这就是 ViewModel 的用途。 例如,如果孩子们有基于枚举或其他什么的特定颜色,对我来说,这是 ChildVM 中的东西,而不是模型本身,并且模型中是否有任何属性指示该颜色,例如该枚举的属性,在这种情况下,是的,我将从 ChildVM 内的模型连接更改通知。 (说实话,我什至可以直接通过 UI 中的颜色转换器来完成此操作,仍然绑定到模型的枚举。这确实是一个具体情况具体分析的事情。)