这篇MSDN文章是否违反了MVVM?

时间:2010-03-21 20:21:43

标签: wcf silverlight entity-framework mvvm

这可能是旧闻,但在2009年3月,本文“Model-View-ViewModel In Silverlight 2 Apps”的代码示例包含DataServiceEntityBase

// COPIED FROM SILVERLIGHTCONTRIB Project for simplicity

/// <summary>
/// Base class for DataService Data Contract classes to implement 
/// base functionality that is needed like INotifyPropertyChanged.  
/// Add the base class in the partial class to add the implementation.
/// </summary>
public abstract class DataServiceEntityBase : INotifyPropertyChanged
{
/// <summary>
/// The handler for the registrants of the interface's event 
/// </summary>
PropertyChangedEventHandler _propertyChangedHandler;

/// <summary>
/// Allow inheritors to fire the event more simply.
/// </summary>
/// <param name="propertyName"></param>
protected void FirePropertyChanged(string propertyName)
{
  if (_propertyChangedHandler != null)
  {
    _propertyChangedHandler(this, new PropertyChangedEventArgs(propertyName));
  }
}

#region INotifyPropertyChanged Members
/// <summary>
/// The interface used to notify changes on the entity.
/// </summary>
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
{
  add
  {
    _propertyChangedHandler += value;
  }
  remove
  {
    _propertyChangedHandler -= value;
  }
}
#endregion

这个类意味着开发人员打算将视觉直接绑定到数据(是的,使用了ViewModel,但它定义了ObservableCollection个数据对象)。这种设计是否偏离了MVVM的指导?现在我可以看到一些原因为什么我们这样做:我们可以用DataServiceEntityBase做什么就是这种事情(与实体框架有密切关系):

// Partial Method to support the INotifyPropertyChanged interface
public partial class Game : DataServiceEntityBase
{
    #region Partial Method INotifyPropertyChanged Implementation
    // Override the Changed partial methods to implement the 
    // INotifyPropertyChanged interface

    // This helps with the Model implementation to be a mostly
    // DataBound implementation

    partial void OnDeveloperChanged() { base.FirePropertyChanged("Developer"); }
    partial void OnGenreChanged() { base.FirePropertyChanged("Genre"); }
    partial void OnListPriceChanged() { base.FirePropertyChanged("ListPrice"); }
    partial void OnListPriceCurrencyChanged() { base.FirePropertyChanged("ListPriceCurrency"); }
    partial void OnPlayerInfoChanged() { base.FirePropertyChanged("PlayerInfo"); }
    partial void OnProductDescriptionChanged() { base.FirePropertyChanged("ProductDescription"); }
    partial void OnProductIDChanged() { base.FirePropertyChanged("ProductID"); }
    partial void OnProductImageUrlChanged() { base.FirePropertyChanged("ProductImageUrl"); }
    partial void OnProductNameChanged() { base.FirePropertyChanged("ProductName"); }
    partial void OnProductTypeIDChanged() { base.FirePropertyChanged("ProductTypeID"); }
    partial void OnPublisherChanged() { base.FirePropertyChanged("Publisher"); }
    partial void OnRatingChanged() { base.FirePropertyChanged("Rating"); }
    partial void OnRatingUrlChanged() { base.FirePropertyChanged("RatingUrl"); }
    partial void OnReleaseDateChanged() { base.FirePropertyChanged("ReleaseDate"); }
    partial void OnSystemNameChanged() { base.FirePropertyChanged("SystemName"); }
    #endregion
}

当然,MSDN代码可以被视为用于教育目的的“玩具代码”,但是在Silverlight开发的真实世界中是否有人这样做?

2 个答案:

答案 0 :(得分:6)

为了使View完全独立于Model,您需要重现在ViewModel中与Model类型相同的类型。

示例

模型包含Person类型,具有FirstNameLastName属性。视觉设计需要“人员列表”,因此有一个包含ListBox的View,该ListBox具有绑定到FirstNameLastName的属性路径的数据模板。 ItemsSource绑定到ViewModel的属性,该属性公开具有FirstNameLastName属性的类型的集合实例。

所以问题是,是否应该有Model Person类型的“ViewModel版本”,或者ViewModel是否应该只重用模型中现有的Person类型? / strong>

在任何一种情况下,你很可能希望这些属性是可观察的。

要考虑

MVVM背后的目标是什么?我们常常喜欢提供一个很好的长列表,列出了模式存在的原因,但在这种情况下,实际上只有2个。

  • 从代码中分离出视觉设计(注意:不设计)。
  • 最大化整个应用程序的可测试表面。

在ViewModel上公开模型类型不会对上述任何一个目标构成障碍。实际上它有助于测试性,因为需要测试的类型和成员的数量减少了。

在我看来,我没有看到实现INotifyPropertyChanged 意味着绑定到视觉效果。某些服务可能希望观察模型对象属性的变化,可能还有其他原因。

将模型与视图分离的关键原则是隐藏有关视图如何从模型本身呈现模型的任何细节。向模型添加ForenameBackColor属性可能会很糟糕。这就是ViewModel的用武之地。

底线

要求模型公开可观察属性并不违反MVVM,它是一个简单而通用的要求,不要求模型具有任何View的任何特定知识,或者确实存在任何“视觉”。< / p>

答案 1 :(得分:3)

不,对我来说很好看 - DataServiceEntityBase 只是他所有DTO /业务对象继承的基类的名称,该设置没有任何问题(这个名字给你带来了什么? )。如果他将他的数据放在ViewModel中,然后将他的View绑定到VM,那么你至少拥有MVVM的VVM部分。

我最担心的是他对 FirePropertyChanged 方法的命名 - 我个人称之为 On PropertyChanged。