我已经阅读了几篇关于MVVM模式的文章,教程和博客文章.但有一件事我不明白.采取三个"层":
据我了解MVVM,模型包含"原始"数据,例如Student类的情况下的名称和地址.视图模型向视图公开属性,该属性表示模型的数据.
视图模型中属性的示例
public string Name {
get { return model.Name; }
set { model.Name = value; }
}
Run Code Online (Sandbox Code Playgroud)
模型示例
private string name;
public string Name {
get { return name; }
set { name = value; }
}
Run Code Online (Sandbox Code Playgroud)
这可能听起来有点愚蠢,但这不会产生冗余吗?为什么我必须在模型和视图模型中保留名称?为什么不能完全处理视图模型上的名称?
该模型是包含业务逻辑的对象图.
这就是你持有行为的地方(验证,计算等).
ViewModel可以模拟UI及其交互.
这些是不同的,并且有不同的原因 - 模式的要点是将显示逻辑与VVM(View和ViewModel)分开,并使您的业务逻辑完全分离.
在这样一个简单的例子中,这个答案是肯定的(这是不合理的冗余).但是,据推测,一个页面将包含的不仅仅是一个Model对象.您可能具有页面状态以及必须全部跟踪的多个其他Model对象.这是在ViewModel中完成的.
例如,您可能具有有关状态栏中显示的登录用户的其他信息,以及运行以检测文本文件更改的服务.
您可能还有一个用于编辑Student对象的表单.如果您打算验证这些更改,那么在验证修改之前,您不希望直接编辑Student对象.在这种情况下,ViewModel可以充当临时存储位置.
关于上述内容的注意事项:在模型中进行验证并不罕见,但即使这样,您也可能希望用户在编辑表单的过程中能够输入无效值.例如,如果您的模型不允许字段中的零长度值,您仍然希望允许用户删除该值,移动到另一个字段(例如,复制它)然后返回到字段,完成编辑(粘贴).如果您直接与模型绑定,那么您的验证逻辑可能无法处理您所希望的"中间","尚未完成"状态.例如,您可能不希望在用户完成并点击"保存"之前将验证错误归咎于您的用户.
您也可能在ViewModel中有Command对象来处理按钮点击等.这些将是特定于域的对象,在模型中无用.
当您需要过滤或以某种方式临时"修改"模型对象以在屏幕上获得有用的东西时,ViewModel也很有用.例如,您可能希望在系统当中的十大演员的实时列表一起显示所有用户的列表(每10秒更新一次).或者你可能想显示报告的列表,并呈现出整体的使用率等过滤,排序和自定义该数据将采取视图模型内发生的图形.
另一方面,模型通常尽可能纯.理想情况下,您只需要POCO(通常)模拟您持久存储中的确切内容(数据库或您拥有的内容).如果您的持久存储具有FirstName和LastName字段,那么您的模型也是如此.只有在ViewModel中才会将它们组合起来以获取名称字段("最后一个"或"最后一个",具体取决于视图的需要).
例如:
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 );
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
518 次 |
| 最近记录: |