2013-01-09 64 views
6

我已阅读了几篇关于MVVM模式的文章,教程和博客文章。但有一件事我不明白。取三个“层次”:MVVM中的模型是什么?

  • 模型
  • 查看
  • 视图模型

据我明白MVVM模型包含的“原始”数据,例如在Student类的情况下的名称和地址。视图模型向视图提供代表模型数据的属性。

例在视图模型

public string Name { 
get { return model.Name; } 
set { model.Name = value; } 
} 

实例属性为模型

private string name; 

public string Name { 
get { return name; } 
set { name = value; } 
} 

这听起来有点傻,但不这样创建一个冗余?为什么我必须在模型和视图模型中保留名称?为什么不应该完全在视图模型上处理名称?

+1

顺便提一下,问题很简单:清晰,简洁并包含示例代码。 – JDB

回答

5

在这样一个简单的例子中,这个答案是肯定的(这是不合理的冗余)。但是,据推测,一个页面将包含的不仅仅是一个单一的模型对象。您可能拥有页面状态以及必须全部跟踪的多个其他模型对象。这是在ViewModel中完成的。

例如,您可能有关于状态栏中显示的已登录用户的附加信息,以及运行检测文本文件更改的服务。

您可能还有一个用于编辑Student对象的窗体。如果您打算验证这些更改,那么在修改完成之前,您不希望直接编辑Student对象。在这种情况下,ViewModel可以充当临时存储位置。

关于上述内容的注意事项:在模型中进行验证并不少见,但即使如此,您仍然希望用户能够在编辑表单的过程中输入无效值。例如,如果您的模型在字段中不允许零长度值,您仍然希望使用户能够删除该值,移动到另一个字段(例如,复制它),然后返回到字段并完成编辑(粘贴)。如果你直接绑定到模型,那么你的验证逻辑可能不会处理这个“中间”,“尚未完成”的状态,只要你愿意。例如,您可能不想在验证错误完成后点击“保存”来提醒用户。

您也可能在ViewModel中有Command对象来处理按钮点击等。这些将是模型中无用的域特定对象。

当您需要过滤或以某种方式暂时“修改”模型对象以获得屏幕上的某些内容时,ViewModels也很有用。例如,您可能想要显示系统中所有用户的列表以及其中前十名执行者的实时列表(每10秒更新一次)。或者您可能想要显示报告列表和显示整体使用率的图表等。在ViewModel中将过滤,排序和自定义数据。

该模型,另一方面,通常是尽可能纯。理想情况下,您只需要POCOs(通常)模拟永久存储(数据库或您有什么)中的内容。如果您的持久存储具有FirstName和LastName字段,那么您的Model也是如此。只有在你的ViewModel中,你可以将它们组合起来以得到一个Name字段(根据视图的需要,可以是“First Last”或“Last,First”)。

例如:在MVVM

namespace Model 
{ 
    public class Student 
    { 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
    } 

    public class Class 
    { 
     public string Name { get; set; } 
     public float Score { get; set; } 
    } 
} 

namespace ViewModel 
{ 
    public class EditStudentRecordViewModel 
    { 
     private Model.Student _student; 
     private IEnumerable<Model.Class> _studentClasses; 

     /* Bind your View to these fields: */ 
     public string FullName 
     { 
      return _student.LastName + ", " + _student.FirstName; 
     } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 

     public IEnumerable<Model.Class> PassingClasses 
     { 
      get 
      { 
       return _studentClasses.Where(c => c.Score >= 78); 
      } 
     } 

     public IEnumerable<Model.Class> FailingClasses 
     { 
      get 
      { 
       return _studentClasses.Where(c => c.Score < 78); 
      } 
     } 

     public void Save() 
     { 
      List<string> l_validationErrors = new List<string>(); 
      if (string.IsNullOrEmpty(this.FirstName)) 
       l_validationErrors.Add("First Name must not be empty."); 
      if (string.IsNullOrEmpty(this.LastName)) 
       l_validationErrors.Add("Last Name must not be empty."); 

      if (l_validationErrors.Any()) 
       return; 

      _student.FirstName = this.FirstName; 
      _student.LastName = this.LastName; 
      Model.Utilities.SaveStudent(_student); 
     } 
    } 
} 
5

该模型是包含您的业务逻辑的对象图。

这就是你持有的行为(验证,计算等)。

ViewModel是模拟UI及其交互的东西。

这些是不同的,并且存在不同的原因 - 模式的要点是将显示逻辑与VVM(View和ViewModel)分开,并将业务逻辑完全分开。

0

模型是完全一样在MVP或Model2的MVC。它是MVC启发模式的一部分,不受主题变化的影响。

模型是包含存储库,工作单元,域/模型对象,数据映射器,服务和一些其他结构的图层。他们结合在一起创建了模型层,其中包含特定应用程序的所有域业务逻辑。

模型不是任何单个实例。否则任何人都会对你产生满足感。

当您无法修改模型层或视图实例,或者两者皆有时,MVVM设计的特定用例就是情况。

P.S.但是,如果您按照ASP.NET MVC文档使用ViewModel实例,那么您实际上并未使用MVVM。它仅仅是Model2 MVC,其中有不同名称的东西(其中“viewmodels”实际上是视图,“views”是模板)。当他们将类似Rails的架构作为“MVC”销售时,他们有点不爽。

4

视图模型是在那里你会跟踪特定于该视图和没有必要的模型属性。

让我们把你的模型,假设它叫做Person

然后创建一个名为PersonViewModelPerson视图模型,它看起来像这样:

public class PersonViewModel 
{ 
    public Person Person { get; set; } 
} 

(请注意,你可能不希望公开这直接与示范,但那是另一回事)

现在让我们假设您在视图中有一个按钮,用于保存Person实例。为了提供更好的用户体验(UX),只有在模型实际发生更改时才需要启用该按钮。所以你实现对PersonINotifyPropertyChanged interface

public class Person : INotifyPropertyChanged 
{ 
    ... 

现在,你可以Person其中Enabled财产的保存按钮将绑定到暴露HasUnsavedChanges属性,但这种逻辑有什么到与该人做什么。

这是视图模型进来时你会在视图模型定义这个视图特定的属性,像这样:

public class PersonViewModel 
{ 
    public Person Person { get; set; } 

    public bool HasUnsavedChanges { get; set; } 
} 

然后,您的视图模型将订阅的的PropertyChanged eventINotifyPropertyChanged界面,并在视图模型上切换HasUnsavedChanges属性。

然后,如果绑定设置正确,当您的模型发生任何更改时,保存按钮将启用/禁用,但您的模型没有任何逻辑将其绑定到视图。

请注意,您还必须在视图模型上实现INotifyPropertyChanged,以及在视图模型发生更改时视图才会选取。

此外,该点作为一个桥梁来包含不属于模型的模型属性和视图属性组合的逻辑。

1

我一直将模型视为应用程序的“构建模块”。它们通常是自包含的类,具有一些属性,并且可能仅对其自己的属性进行一些基本的验证或逻辑。

另一方面,查看模型是我的实际应用程序类,最终在构建和运行应用程序时使用“构建块”(模型)。他们不喜欢的东西执行先进的验证,过程的命令,处理事件,任何种类的业务逻辑等

应当注意的是,你不暴露你的模型的属性在你的视图模型就像你在有你的示例代码。这样做是因为“模型层”与“视图”层完全分离,因此将“整个模型”公开给视图也是完全可以接受的。这是我通常在大多数小型项目中使用的原因,因为它简单并且没有代码重复。

public MyModel CurrentModel 
{ 
    get { return _model; } 
    set 
    { 
     if (_model != value) 
     { 
      _model = value; 
      RaisePropertyChanged("CurrentModel"); 
     } 
    } 
} 

但是,如果有其中只从模式中的一些特性需要在查看情况,或者如果项目足够大,我会希望保持层完全分离,然后我暴露我的模特通过ViewModel的视图属性,就像你在示例代码中一样。