这可能是旧闻,但在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开发的真实世界中是否有人这样做?
答案 0 :(得分:6)
为了使View完全独立于Model,您需要重现在ViewModel中与Model类型相同的类型。
示例强>
模型包含Person
类型,具有FirstName
和LastName
属性。视觉设计需要“人员列表”,因此有一个包含ListBox的View,该ListBox具有绑定到FirstName
和LastName
的属性路径的数据模板。 ItemsSource
绑定到ViewModel的属性,该属性公开具有FirstName
和LastName
属性的类型的集合实例。
所以问题是,是否应该有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。