如何使用集合构建MVVM?

时间:2011-08-24 16:15:18

标签: wpf mvvm

在涉及列表/集合时,我无法理解如何应用MVVM模式。

假设MainModel有一些属性和方法,以及包含其他DetailModel个对象的列表。可以添加,删除或重新排序DetailModel个对象。

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

最后,有一个MainViewModel。这个属性由MainModel的属性和方法支持,绑定到主视图,更改通知保持所有内容同步。 (到目前为止,我对这种模式感到满意 - 如果有一些我缺少的基本内容,请更多说明这一点......)

在处理清单时,我感到困惑。我遇到过几个示例,其中MainViewModel只是将DetailModels的列表公开给视图,而DetailModelViews直接绑定到模型。这个功能,但是有问题。它并不一贯遵循模式(没有DetailViewModel存在),它促使我在我的细节模型中包含一些与UI相关的代码。我似乎很清楚,MainViewModel应该为要绑定的UI公开DetailViewModels列表,但我仍然坚持如何实现这样的事情!

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

4 个答案:

答案 0 :(得分:12)

通常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}}

答案 1 :(得分:5)

您拥有单独的DetailModels列表和DetailViewModels列表是正确的。 DetailViewModels列表应该是ObservableCollection<DetailViewModel>类型的属性。您可以在设置模型时填充可观察列表(如果将模型传递给ViewModel的构造函数,则可以在构造时填充。)

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

您可以订阅m_details。CollectionChanged。您可以在此处理模型中列表内容的重新排序。

我希望这会有所帮助。

答案 2 :(得分:2)

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

通常,主VM的构造函数如下所示:

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

其中MasterModel.DetailDetailModel个对象的集合,_Detail是展示给视图的Detail属性的支持字段。

就添加,删除和重新排序此列表中的项目而言,在UI中至少这将通过MasterViewModel上的命令完成,这些命令必须同时操作MasterModel.Detail和{{ 1}}。这有点痛苦,但除非您想在每次更改MasterViewModel.Detail后重新填充MasterViewModel.Detail,否则这是不可避免的。

另一方面,如果你一直想知道“为什么我需要为视图模型编写单元测试?”,现在你知道了。

答案 3 :(得分:1)

我认为这是一个答案,我认为使用ObservableViewModelCollection<TViewModel, TModel>

很好地解决了这个问题

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

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

请注意我对SL与WPF的评论