MVVM中的模型是用来做什么的

本文关键字:什么 模型 MVVM | 更新日期: 2023-09-27 17:51:03

我读了几篇关于MVVM模式的文章、教程和博客文章。但是有一件事我不明白。选取三个"图层":

  • <
  • 视图/gh>

就我所理解的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; }
}

这可能听起来有点愚蠢,但这不会造成冗余吗?为什么我必须在模型和视图模型中保留名称?为什么不应该完全处理视图模型上的名称?

MVVM中的模型是用来做什么的

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

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

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

上面的注意:在模型中发生验证并不罕见,但即使这样,您也可能希望用户能够在编辑表单的过程中输入无效的值。例如,如果您的模型不允许字段中的零长度值,您仍然希望允许用户删除该值,移动到另一个字段(例如,复制它),然后返回到该字段并完成编辑(粘贴)。如果您直接绑定到模型,那么您的验证逻辑可能无法像您希望的那样处理这种"中间"、"尚未完成"的状态。例如,在用户完成验证并点击"保存"之前,你可能不想让用户发现验证错误。

您可能还会在ViewModel中使用Command对象来处理按钮单击等操作。这些将是特定于领域的对象,在模型中是无用的。

当你需要过滤或临时"修改"模型对象以在屏幕上获得有用的东西时,ViewModels也很有用。例如,您可能希望显示系统中所有用户的列表,以及其中表现最好的10个用户的实时列表(每10秒更新一次)。或者,您可能希望显示报表列表和显示总体使用率的图表等。筛选、排序和自定义数据将在ViewModel中进行。

另一方面,模型通常是尽可能纯净的。理想情况下,您只希望poco(通常)准确地模拟持久存储(数据库或其他存储)中的内容。如果您的持久存储有FirstName和LastName字段,那么您的Model也有。只有在你的ViewModel中,你才能将它们组合起来获得一个Name字段(根据视图的需要,要么是"First Last",要么是"Last, First")。

例如:

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 );
        }
    }
}

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

这是保存行为(验证,计算等)的地方。

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

它们是不同的,存在的原因也不同——模式的要点是将你的显示逻辑与VVM (View和ViewModel)分离,并将你的业务逻辑完全分离。

视图模型是您跟踪特定于视图而不是模型的属性的地方。

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

然后为Person创建一个名为PersonViewModel的视图模型,如下所示:

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

(注意,您可能不希望像这样直接公开模型,但那是另一回事)

现在假设视图中有一个按钮用于保存Person实例。为了提供更好的用户体验(UX),您希望仅在模型实际更改时才启用该按钮。因此,在Person类上实现INotifyPropertyChanged接口:

public class Person : INotifyPropertyChanged
{
    ...

现在,您可以从您的Person中暴露HasUnsavedChanges属性,保存按钮上的Enabled属性将绑定到该属性,但该逻辑与无关。这就是视图模型的用武之地。您可以在视图模型上定义这个特定于视图的属性,如下所示:

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

然后,视图模型将订阅INotifyPropertyChanged接口的PropertyChanged事件,并切换视图模型上的HasUnsavedChanges属性。

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

请注意,您还必须在视图模型上实现INotifyPropertyChanged,以便您的视图在对绑定到的视图模型进行更改时拾取。

再一次,这个点作为一个桥梁来包含逻辑,这个逻辑是模型属性和不属于模型的视图属性的组合。

MVVM中的模型与MVP或Model2 MVC中的模型完全相同。这是mvc样式中唯一不受主题变化影响的部分。

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

Model不是任何单个实例。任何跟你说不一样的人都是胡说八道。

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

<子> 注:但是,如果您使用的是ViewModel实例。. NET MVC文档,那么你实际上没有使用MVVM。它只是具有不同名称的Model2 MVC(其中"视图模型"实际上是视图,"视图"是模板)。当他们把类似rails的架构称为"MVC"时,他们搞砸了。

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

另一方面,视图模型是在构建和运行应用程序时最终使用"构建块"(模型)的实际应用程序类。它们执行高级验证、处理命令、处理事件、任何类型的业务逻辑等。

应该注意的是,你没有在你的ViewModel中暴露你的模型的属性,就像你在你的示例代码中那样。这样做是"MVVM纯粹主义者"的方法,因为它完全将你的模型层从视图层中分离出来,然而,将整个模型公开给视图也是完全可以接受的。这是我通常在大多数小项目中使用的方法,因为它简单且缺乏代码重复。

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

但是,如果在视图中只需要模型的几个属性,或者如果项目足够大,我想要保持图层完全分开,那么我通过ViewModel将模型的属性暴露给视图,就像您在示例代码中所做的那样。