2011-08-24 40 views
17

我无法理解如何在涉及到列表/集合时应用MVVM模式。如何使用集合构造MVVM?

说出MainModel有几个属性和方法,以及含有其他DetailModel对象的列表。 DetailModel对象可以添加,删除或重新排序。

的的MainView会显示相关的根模式中的一些控制,并可以从列表中填充的列表框。每个项目都将通过DetailModelView UserControl拥有自己的子视图。

最后,有一个MainViewModel。它具有由MainModel的属性和方法支持的属性,绑定到主视图,更改通知使所有内容保持同步。 (到现在为止,我很舒服的模式 - 更多的情况下,说明这有我丢失的东西根本...)

当涉及到处理名单,我感到困惑。我遇到了几个例子,其中MainViewModel只是将DetailModel的列表公开给视图,而DetailModelViews直接绑定到模型上。这功能,但是有问题。它并不总是遵循该模式(不存在DetailViewModel),并且它促使我在我的详细模型中包含一些与UI相关的代码。在我看来,MainViewModel应该公开一个用于UI绑定的DetailViewModel列表,但我坚持如何实现这样的事情!

应该如何管理两个列表(DetailModels和DetailViewModels)?我真的很困惑,因为我最初填充DetailViewModel列表,以及如何处理添加,删除或更改项目的顺序以保持它们的同步!

回答

9

通常Models只不过是数据对象。他们不应该包含任何代码来执行诸如从列表中添加/删除项目等操作。这是ViewModel's工作。

在你的情况,我会创建一个MainViewModel具有以下特性:

  • ObservableCollection<DetailViewModel> Details
  • ICommand AddDetailCommand
  • ICommand RemoveDetailCommand

如果您MainModel类是一个数据对象,可以将其公开,也可以是MainViewModel的属性。公开它的属性是“MVVM纯粹”方法,而公开整个模型有时更实用。您的MainViewModel负责创建初始列表DetailViewModels,并负责添加/删除这些项目。例如,在PropertyChanged事件为MainViewModel.MainModel属性,它可能会重建MainViewModel.Details收集和CollectionChanged事件的MainViewModel.Details属性将更新MainViewModel.MainModel.Details

+1

这非常简洁地描述了最终解决方案。我的“MainViewModel”也有命令将列表中的选定项目向上或向下移动... – mbmcavoy

4

你是对有一个单独的DetailModels列表和DetailViewModels列表。 DetailViewModels列表应该是ObservableCollection<DetailViewModel>类型的属性。当您设置模型(或在构造的时候,如果你通过模型到您的视图模型的构造函数)。

private ObservableCollection<DetailViewModel> m_details; 
public IEnumerable<DetailViewModel> Details 
{ 
    get { return m_details; } 
} 

您可以订阅m_details可以填充可观察名单。 CollectionChanged。这是您可以处理模型中列表内容重新排序的地方。

我希望这会有所帮助。

2

以我的经验,唯一一次用暴露模型对象的视图脱身是如果你正在做简单的只读呈现,例如在ComboBox中显示一个字符串属性。如果存在任何涉及该对象的实际UI(特别是涉及双向数据绑定的UI),则需要视图模型。

通常情况下,主虚拟机的构造看起来像这样:

public MasterViewModel(MasterModel m) 
{ 
    _Model = m; 
    _Detail = new ObservableCollection<DetailViewModel>(m.Detail); 
} 

其中MasterModel.DetailDetailModel对象的集合,并_Detail是针对使用者容易看到一个Detail属性支持字段。

至于添加,删除,重新排序并在该列表中的项目而言,在UI至少这将通过命令行MasterViewModel来完成,它必须既操纵和MasterModel.DetailMasterViewModel.Detail。这有点痛苦,但除非你想在MasterModel.Detail的每次更改后重新填充MasterViewModel.Detail,否则这实在是不可避免的。另一方面,如果您想知道“为什么我需要为视图模型编写单元测试?”,现在您知道了。

+0

我还在我的解决办法,但我想在这里指出一个很大的帮助:“每次更改后重新填充MasterViewModel.Detail MasterModel.Detail“奇怪的是,这种想法并没有发生在我身上!我必须在初始化时建立它,所以我可以随时重建。 – mbmcavoy

+2

我在想'新的ObservableCollection (m.Detail);'会起作用,因为'm.Detail'的类型与通过ObservableCollection泛型指定为''的类型不同。我怀疑它会起作用。 –

1

这里有一个答案,我认为解决这个问题非常漂亮的使用ObservableViewModelCollection<TViewModel, TModel>

这很好,懒惰。它在ctor中需要一个ObservableCollection和一个ViewModelFactory。我喜欢它,因为它保持它所属模型层的状态。 GUI上的用户操作可以在VM上通过公共方法调用M上的命令,任何M层产生的更改都将由该链接中的类自动处理。

https://stackoverflow.com/q/2177659/456490

注意我的关于SL与WPF评论