【问题标题】:Does this MSDN article violate MVVM?这篇 MSDN 文章是否违反了 MVVM?
【发布时间】:2010-03-21 20:21:43
【问题描述】:

这可能是旧闻,但早在 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 开发的真实世界中是否有人在做类似的事情?

【问题讨论】:

  • 相当煽动性的标题 - 你有什么理由在同一句话中喷出某人的名字和“违反”这个词?
  • 宅男:问题正文中明确说明了我的推理。
  • 不,这不是针对某个人的原因。您是在专门呼唤一个人,因此可能会因为您自己的误解而抹黑他们。其次,Shawn 必须有一位编辑来批准所发布的内容,但我没有看到您因任何违规行为或特定编辑的姓名而指责 MSDN。最后,也是最重要的一点,如果您阅读了这篇文章,Shawn 特别指出 此示例不一定代表实际代码的使用方式。它只是为了解释模式而设计的。。我已将此帖子标记为具有攻击性。
  • 伟大的工作。你在保护无辜者。
  • @rasx:尽管 AnthonyWJones 编辑了你的标题,但你似乎并不后悔。我,同样,正在标记攻击性。请淡化花言巧语并提出“好”的问题。我们不是来打架的。

标签: wcf silverlight entity-framework mvvm


【解决方案1】:

为了使 View 完全独立于 Model,您需要复制在许多情况下与 ViewModel 中的 Model 类型相同的类型。

示例

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

那么问题来了,应该有一个“ViewModel 版本”的 Model Person 类型,还是 ViewModel 应该简单地重新使用 Model 中现有的 Person 类型?

在任何一种情况下,您都希望属性是可观察的。

考虑

MVVM 背后的目标是什么?很多时候,我们喜欢提供一个很好的长列表,说明为什么存在模式,但在这种情况下,实际上只有 2 个。

  • 将视觉设计(注意:非设计)与代码分开。
  • 最大化整个应用程序的可测试表面。

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

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

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

底线

要求模型公开可观察属性并不违反 MVVM,它是一个简单而通用的要求,不需要模型对任何视图有任何特定的了解,或者根本不需要涉及任何“视觉效果”。

【讨论】:

  • 我要记住一件非常重要的事情:“在我看来,我认为实现 INotifyPropertyChanged 并不意味着绑定到视觉对象。某些服务可能想要观察属性的变化可能还有其他原因一个模型对象。”
【解决方案2】:

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

主要让我感到不安的是他对FirePropertyChanged 方法的命名——我个人会称它为OnPropertyChanged。

【讨论】:

    猜你喜欢
    • 2010-11-01
    • 2014-02-15
    • 2010-11-29
    • 1970-01-01
    • 2015-05-19
    • 2015-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-15
    相关资源
    最近更新 更多