WPF / MVVM:将域模型集合委派给ViewModel

时间:2010-05-25 17:30:45

标签: wpf mvvm dns delegates collections

域模型集合(通常是List或IEnumerable)委派到ViewModel。

这意味着我的CustomerViewModel有一个List或IEnumerable类型的订单集合。

绑定控件无法识别列表中的更改。但是使用ObservableCollection它是。

这是MVVM设计模式中的一个问题。

你如何应对?

更新:我如何做的示例:

 public class SchoolclassViewModel : ViewModelBase
{
    private Schoolclass _schoolclass;
    private ObservableCollection<PupilViewModel> _pupils = new ObservableCollection<PupilViewModel>();        

    public SchoolclassViewModel(Schoolclass schoolclass)
    {
        _schoolclass = schoolclass;
        _schoolclass.Pupils = new List<Pupil>();

        foreach (var p in schoolclass.Pupils)           
            Pupils.Add(new PupilViewModel(p));            
    }

    public Schoolclass GetSchoolclass 
    {
        get { return _schoolclass; } 
    }

    public int ID { get; set; }       

    public string SchoolclassName
    {
        get { return _schoolclass.SchoolclassName;}
        set
        { 
            if(_schoolclass.SchoolclassName != value)
            {                    
                _schoolclass.SchoolclassName = value;
                this.RaisePropertyChanged("SchoolclassName");
            }

        }
    }   

    public ObservableCollection<PupilViewModel> Pupils
    {
        get{ return _pupils;}
        set
        {
            _pupils = value;
            this.RaisePropertyChanged("Pupils");
        } 
    }
}

3 个答案:

答案 0 :(得分:3)

我通过不按照你描述的方式来解决这个问题。

如果我需要在视图中显示Foo对象及其相关的Bar对象,FooViewModel通常会实现类型为Bars的{​​{1}}属性}。

请注意,这与底层ObservableCollection<BarViewModel>类是否具有Foo类型的Bars属性无关。 IEnumerable<Bar>类可能不会。除了UI之外,应用程序甚至可能无法迭代Foo的所有Bar个对象。

修改

当我的视图是应用程序对象模型的简单表示时,我几乎像你在样本中那样做。我的构造函数中的代码通常更紧凑:

Foo

但它基本上是一样的。

但是这假设_Bars = new ObservableCollection<BarViewModel>( _Foo.Bars.Select(x => new BarViewModel(x))); 实际上暴露了Foo属性。它可能不会。或者也许只有一些Bars个对象应该出现在视图中。或者也许它们应该与其他对象混合在一起,Bar应该展示某种FooViewModel

我要说的是视图模型是视图的模型。这不一定与底层对象模型直接对应。

选择一个简单的例子:我的程序可以通过将项目拖放到五个不同的CompositeCollection控件中,为用户提供将项目分为五个不同类别的方法。最终,这样做会在ListBox对象上设置Category属性。我的视图模型将包含Item个对象的集合,每个对象都具有类型CategoryViewModel的属性,因此在集合之间来回拖动项目很容易实现。

问题是,在应用程序的对象模型中甚至可能没有 一个ObservableCollection<ItemViewModel>类,更不用说Category个对象的集合了。 Category可能只是Item.Category类型的属性。 string未镜像应用程序的对象模型。它仅用于支持UI中的视图。

答案 1 :(得分:0)

好的,我会继续添加我的想法作为答案,而不是在评论中。 :)

我认为最重要的是,这只是WPF和数据绑定工作方式的现实。为了使双向数据绑定能够运行,集合需要一种通知绑定到它们的控件的方法,并且大多数域对象中使用的标准列表和集合不会/不会/不应该支持它。正如我在评论中提到的,要求为非集合属性实现INotifyPropertyChanged是标准域对象可能无法满足的另一个要求。

域对象不打算成为视图模型,因此您可能会发现需要在两种类型的对象之间来回映射。这与必须在域对象和数据访问对象之间来回映射并没有什么不同。每种类型的对象在系统中都有不同的功能,每种对象都应专门设计用于支持自己在系统中的作用。

所有这一切,Agies关于使用AOP自动生成代理类的想法非常有趣,我打算深入研究。

答案 2 :(得分:0)

我所做的不是在我的域模型中使用ObservableCollection而是使用我自己的集合类型,该类型在其他有用的标准和自定义接口中实现INotifyCollectionChanged接口。我的思维方式就像Rockford Lhotka在他的书中建议的那样,更改通知不仅仅适用于表示层,因为域层中的其他业务对象在另一个对象中的状态更改时通常需要某种通知。

使用这种方法,您可以创建自己的集合类型,它仍然具有更改通知的好处,以及您需要的自定义行为。您的集合的基类可以实现为纯粹的基础结构代码,然后可以使用this book中使用的子类型分层技术创建可包含业务逻辑的子类。所以最后你可以拥有一个可以包装IEnumerable&lt;&gt;类型的集合。并提供您正在寻找的域名模型和演示文稿代码的更改通知内容。