什么是MVC中的ViewModel?


429

我是ASP.NET MVC的新手。我在理解ViewModel的目的时遇到了问题。

什么是ViewModel?为什么我们需要ASP.NET MVC应用程序的ViewModel?

如果我有一个很好的例子说明它的工作和解释,那就更好了。


4
这篇文章就是您所寻找的-“什么是ASP.NET MVC ViewModel?”
尤苏波夫2012年

6
这篇文章看起来很棒:rachelappel.com/…–
Andrew

Answers:


607

A view model表示您要在视图/页面上显示的数据,无论是用于静态文本还是可以添加到数据库(或编辑)的输入值(例如文本框和下拉列表)。这与您的有所不同domain model。它是视图的模型。

让我们说您有一个Employee代表您的员工域模型的类,它包含以下属性(唯一标识符,名字,姓氏和创建日期):

public class Employee : IEntity
{
     public int Id { get; set; }

     public string FirstName { get; set; }

     public string LastName { get; set; }

     public DateTime DateCreated { get; set; }
}

视图模型与域模型的不同之处在于,视图模型仅包含您要在视图上使用的数据(以属性表示)。例如,假设您要添加新的员工记录,则视图模型可能如下所示:

public class CreateEmployeeViewModel
{
     public string FirstName { get; set; }

     public string LastName { get; set; }
}

如您所见,它仅包含两个属性。这两个属性也在雇员域模型中。您为什么会问这个? Id可能不是从视图中设置的,它可能是由Employee表自动生成的。并且DateCreated也可以在存储过程或应用程序的服务层中进行设置。因此IdDateCreated视图模型中不需要。当您以静态文本查看员工的详细信息(已被捕获的员工)时,可能要显示这两个属性。

加载视图/页面时,员工控制器中的create action方法将创建此视图模型的实例,如果需要,可填充任何字段,然后将此视图模型传递给视图/页面:

public class EmployeeController : Controller
{
     private readonly IEmployeeService employeeService;

     public EmployeeController(IEmployeeService employeeService)
     {
          this.employeeService = employeeService;
     }

     public ActionResult Create()
     {
          CreateEmployeeViewModel model = new CreateEmployeeViewModel();

          return View(model);
     }

     public ActionResult Create(CreateEmployeeViewModel model)
     {
          // Do what ever needs to be done before adding the employee to the database
     }
}

您的视图/页面可能看起来像这样(假设您正在使用ASP.NET MVC并且使用了Razor视图引擎):

@model MyProject.Web.ViewModels.CreateEmployeeViewModel

<table>
     <tr>
          <td><b>First Name:</b></td>
          <td>@Html.TextBoxFor(m => m.FirstName, new { maxlength = "50", size = "50" })
              @Html.ValidationMessageFor(m => m.FirstName)
          </td>
     </tr>
     <tr>
          <td><b>Last Name:</b></td>
          <td>@Html.TextBoxFor(m => m.LastName, new { maxlength = "50", size = "50" })
              @Html.ValidationMessageFor(m => m.LastName)
          </td>
     </tr>
</table>

因此,只能在FirstName和上进行验证LastName。使用FluentValidation,您可能会进行如下验证:

public class CreateEmployeeViewModelValidator : AbstractValidator<CreateEmployeeViewModel>
{
     public CreateEmployeeViewModelValidator()
     {
          RuleFor(m => m.FirstName)
               .NotEmpty()
               .WithMessage("First name required")
               .Length(1, 50)
               .WithMessage("First name must not be greater than 50 characters");

          RuleFor(m => m.LastName)
               .NotEmpty()
               .WithMessage("Last name required")
               .Length(1, 50)
               .WithMessage("Last name must not be greater than 50 characters");
     }
}

有了数据注释,它可能看起来像这样:

public class CreateEmployeeViewModel : ViewModelBase
{
    [Display(Name = "First Name")]
    [Required(ErrorMessage = "First name required")]
    public string FirstName { get; set; }

    [Display(Name = "Last Name")]
    [Required(ErrorMessage = "Last name required")]
    public string LastName { get; set; }
}

要记住的关键是,视图模型仅代表您要使用的数据,没有别的。如果您有一个具有30个属性的域模型,并且只想更新一个值,则可以想象所有不必要的代码和验证。在这种情况下,您将在视图模型中仅拥有一个值/属性,而没有域对象中的所有属性。

一个视图模型可能不仅具有来自一个数据库表的数据。它可以合并来自另一个表的数据。以上面关于添加新员工记录的示例为例。除了仅添加名字和姓氏之外,您可能还需要添加员工的部门。该部门列表将来自您的Departments表格。因此,现在您可以在一个视图模型中获得来自EmployeesDepartments表的数据。此时,您需要将以下两个属性添加到视图模型中,并用数据填充它:

public int DepartmentId { get; set; }

public IEnumerable<Department> Departments { get; set; }

在编辑员工数据(已经添加到数据库中的员工)时,与上面的示例没有太大区别。创建一个视图模型,例如EditEmployeeViewModel。仅具有要在此视图模型中编辑的数据,例如名字和姓氏。编辑数据,然后单击提交按钮。我不必担心该Id字段,因为该Id值可能在URL中,例如:

http://www.yourwebsite.com/Employee/Edit/3

借此Id并通过与您的名字和姓氏值传递到您的存储库层,在一起。

删除记录时,通常遵循与编辑视图模型相同的路径。我也会有一个URL,例如:

http://www.yourwebsite.com/Employee/Delete/3

当视图首次加载时,我将使用的Id3 从数据库中获取员工的数据。然后,我将仅在视图/页面上显示静态文本,以便用户可以看到正在删除的员工。当用户单击“删除”按钮时,我只需要使用Id值3并将其传递给我的存储库层。您只需Id要从表中删除记录。

还有一点,您并不需要每个动作都需要一个视图模型。如果是简单数据,则仅使用即可EmployeeViewModel。如果是复杂的视图/页面并且它们彼此不同,那么我建议您为每个视图使用单独的视图模型。

我希望这可以消除您对视图模型和域模型的任何困惑。


5
@Kenny:然后显示它:)我想说的是,假设您有一个包含50个属性的域模型,并且视图仅需要显示5个,那么仅发送5个就不能发送所有50个属性
Brendan沃格特

5
@BrendanVogt –您对此做得很好,但是我不明白“发送全部50个房产”的成本是多少。其他代码已经创建了一个具有全部50个属性的Model对象,似乎仅为了发送45个属性而维护另一个类似乎就不值得-特别是如果将来可能要发送这45个属性中的任何一个。
肯尼·埃维特

5
@BrendanVogt –我想也许LukLed的回答可以帮助我理解为什么它们可能有用,特别是ViewModel(可以)“ ...合并来自不同数据库实体的值” [在这里我假设该短语与“ true”一样。数据库实体”替换为“模型对象”]。但是,ViewModels打算解决哪些具体问题?你有链接吗?我自己找不到任何东西。[我很抱歉,如果我似乎是在挑剔你!]
肯尼·埃维特

1
我刚刚听说有人说ViewModels是将多个集合(或跨模型属性)发送到单个视图中的好方法,而不必将它们填充到viewBag中。我感觉合理。
Ayyash 2014年

3
抱歉,我很抱歉,但是很遗憾,这个答案还不完整。将视图模型定义为仅在页面上需要显示的内容就像问“什么是汽车?” 并收到答案“不是飞机”。好吧,那是真的,但不是很有帮助。VM的更正确定义是“呈现页面所需的一切”。如果您从头开始,我已经确定了正确而轻松地构建VM所需的组件,在许多情况下,它们利用了您现有的域模型和表示模型。
山姆

133

视图模型是一个类,代表特定视图中使用的数据模型。我们可以将此类用作登录页面的模型:

public class LoginPageVM
{
    [Required(ErrorMessage = "Are you really trying to login without entering username?")]
    [DisplayName("Username/e-mail")]
    public string UserName { get; set; }
    [Required(ErrorMessage = "Please enter password:)")]
    [DisplayName("Password")]
    public string Password { get; set; }
    [DisplayName("Stay logged in when browser is closed")]
    public bool RememberMe { get; set; }
}

使用此视图模型,您可以定义视图(Razor视图引擎):

@model CamelTrap.Models.ViewModels.LoginPageVM

@using (Html.BeginForm()) {
    @Html.EditorFor(m => m);
    <input type="submit" value="Save" class="submit" />
}

和动作:

[HttpGet]
public ActionResult LoginPage()
{
    return View();
}

[HttpPost]
public ActionResult LoginPage(LoginPageVM model)
{
    ...code to login user to application...
    return View(model);
}

产生此结果的结果(提交表单后显示屏幕,带有验证消息):

如您所见,视图模型具有许多角色:

  • 视图模型通过仅包含视图中表示的字段来记录视图。
  • 视图模型可能包含使用数据批注或IDataErrorInfo的特定验证规则。
  • 查看模型定义视图应该是什么样子(为LabelForEditorForDisplayFor佣工)。
  • 视图模型可以合并来自不同数据库实体的值。
  • 您可以轻松地为视图模型指定显示模板,并使用DisplayFor或EditorFor助手在许多地方重复使用它们。

视图模型及其检索的另一个示例:我们要显示基本的用户数据,他的特权和用户名。我们创建一个特殊的视图模型,其中仅包含必填字段。我们从数据库中的不同实体检索数据,但是视图仅知道视图模型类:

public class UserVM {
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public bool IsAdministrator { get; set; }
    public string MothersName { get; set; }
}

恢复:

var user = db.userRepository.GetUser(id);

var model = new UserVM() {
   ID = user.ID,
   FirstName = user.FirstName,
   LastName = user.LastName,
   IsAdministrator = user.Proviledges.IsAdministrator,
   MothersName = user.Mother.FirstName + " " + user.Mother.LastName
} 

我瘦了user.Mother.FirstName +“” + user.Mother.LastName应该在View Model End中完成。所有逻辑都应在视图模型端完成。
Kurkula 2015年

3
@Chandana:我相信可以在视图模型中进行简单的串联。如果要同时显示两个字段,则没有理由公开两个字段。
2015年

82

编辑:我在我的博客上更新了此答案:

http://www.samwheat.com/post/The-function-of-ViewModels-in-MVC-web-development

我的回答有点冗长,但是我认为将视图模型与其他常用模型进行比较很重要,以了解它们为什么不同以及为什么必要。

总结并直接回答所提出的问题:

一般来说,视图模型是一个对象,其中包含呈现视图所需的所有属性和方法。视图模型属性通常与诸如客户和订单之类的数据对象相关,此外,它们还包含与页面或应用程序本身相关的属性,例如用户名,应用程序名称等。视图模型提供了一个方便的对象,可以传递给渲染引擎以创建一个html页面。使用视图模型的许多原因之一是,视图模型提供了一种对某些表示任务进行单元测试的方法,例如处理用户输入,验证数据,检索数据以供显示等。

这是实体模型(也称为DTO的a.ka.模型),表示模型和视图模型的比较。

数据传输对象又称“模型”

数据传输对象(DTO)是一个类,其属性与数据库中的表模式匹配。DTO因其在往返数据存储中的数据穿梭的常用用法而命名。
DTO的特点:

•是业务对象–它们的定义取决于应用程序数据。

•通常只包含属性-没有代码。

•主要用于与数据库之间的数据传输。

•属性与数据存储中特定表上的字段完全或紧密匹配。

数据库表通常被规范化,因此DTO也通常被规范化。这使得它们在呈现数据方面用途有限。但是,对于某些简单的数据结构,它们通常做得很好。

这是DTO的两个示例:

public class Customer
{
    public int ID { get; set; }
    public string CustomerName { get; set; }
}


public class Order
{
    public int ID { get; set; }
    public int CustomerID { get; set; }
    public DateTime OrderDate { get; set; }
    public Decimal OrderAmount { get; set; }
}

展示模型

表示模型是一种实用程序类,用于在屏幕或报表上呈现数据。表示模型通常用于对由多个DTO的数据组成的复杂数据结构进行建模。表示模型通常代表数据的非规范化视图。

表示模型的特征:

•是业务对象–它们的定义取决于应用程序数据。

•主要包含属性。代码通常仅限于格式化数据或与DTO相互转换。表示模型不应包含业务逻辑。

•通常会显示非规范化的数据视图。也就是说,它们通常合并多个DTO的属性。

•通常包含与DTO不同的基本类型的属性。例如,美元金额可以表示为字符串,因此它们可以包含逗号和货币符号。

•通常由它们的使用方式及其对象特征来定义。换句话说,用作渲染网格的支持模型的简单DTO实际上也是该网格上下文中的表示模型。

表示模型“按需”和“按需”使用(而DTO通常与数据库模式相关联)。表示模型可以用于为整个页面,页面上的网格或页面上的网格上的下拉列表的数据建模。表示模型通常包含其他表示模型的属性。表示模型通常是为一次性使用而构造的,例如在单个页面上呈现特定的网格。

演示模型示例:

public class PresentationOrder
{
    public int OrderID { get; set; }
    public DateTime OrderDate { get; set; }
    public string PrettyDate { get { return OrderDate.ToShortDateString(); } }
    public string CustomerName { get; set; }
    public Decimal OrderAmount { get; set; }
    public string PrettyAmount { get { return string.Format("{0:C}", OrderAmount); } }
}

查看模型

视图模型类似于表示模型,它是用于渲染视图的后备类。但是,它的构造与Presentation Model或DTO完全不同。视图模型通常包含与表示模型和DTO相同的属性,因此,它们常常彼此混淆。

视图模型的特征:

•是用于呈现页面或屏幕的单一数据源。通常,这意味着视图模型将公开页面上任何控件需要正确呈现自身的每个属性。使视图模型成为视图的单一数据源可以极大地提高其功能和单元测试价值。

•是复合对象,其包含由应用程序数据以及应用程序代码使用的属性组成的属性。当设计视图模型的可重用性时,此特性至关重要。下面的示例对此进行了讨论。

•包含应用程序代码。视图模型通常包含在渲染过程中以及用户与页面交互时调用的方法。该代码通常与事件处理,动画,控件的可见性,样式等相关。

•包含调用业务服务以获取数据或将其发送到数据库服务器的代码。该代码通常被错误地放置在控制器中。从控制器调用业务服务通常会限制视图模型对单元测试的有用性。需要明确的是,视图模型本身不应包含业务逻辑,而应调用包含业务逻辑的服务。

•通常包含属性,这些属性是其他页面或屏幕的其他视图模型。

•写为“每页”或“每个屏幕”。通常为应用程序中的每个页面或屏幕编写一个唯一的视图模型。

•通常是从基类派生的,因为大多数页面和屏幕都具有相同的属性。

查看模型组成

如前所述,视图模型是组合对象,因为它们在单个对象上组合了应用程序属性和业务数据属性。视图模型上常用的应用程序属性示例包括:

•用于显示应用程序状态的属性,例如错误消息,用户名,状态等。

•用于格式化,显示,样式化或动画化控件的属性。

•用于数据绑定的属性,例如列表对象和保存用户输入的中间数据的属性。

以下示例说明了为什么视图模型的复合性质很重要,以及如何最好地构建高效且可重用的视图模型。

假设我们正在编写一个Web应用程序。应用程序设计的要求之一是必须在每个页面上显示页面标题,用户名和应用程序名称。如果我们要创建一个页面来显示演示文稿订单对象,则可以如下修改演示文稿模型:

public class PresentationOrder
{
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }
    public int OrderID { get; set; }
    public DateTime OrderDate { get; set; }
    public string PrettyDate { get { return OrderDate.ToShortDateString(); } }
    public string CustomerName { get; set; }
    public Decimal OrderAmount { get; set; }
    public string PrettyAmount { get { return string.Format("{0:C}", OrderAmount); } }
}

这种设计可能有效……但是,如果我们要创建一个显示订单列表的页面怎么办?PageTitle,UserName和ApplicationName属性将重复出现,并且难以使用。另外,如果我们想在类的构造函数中定义一些页面级逻辑,该怎么办?如果我们为要显示的每个订单创建一个实例,我们将无法再这样做。

组成重于继承

这是一种我们可以重构订单表示模型的方法,以使其成为真实的视图模型,并且对于显示单个PresentationOrder对象或PresentationOrder对象的集合很有用:

public class PresentationOrderVM
{
    // Application properties
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }

    // Business properties
    public PresentationOrder Order { get; set; }
}


public class PresentationOrderVM
{
    // Application properties
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }

    // Business properties
    public List<PresentationOrder> Orders { get; set; }
}

通过查看以上两个类,我们可以看到思考视图模型的一种方法是它是一个表示模型,其中包含另一个表示模型作为属性。顶层表示模型(即视图模型)包含与页面或应用程序相关的属性,而表示模型(属性)包含与应用程序数据相关的属性。

我们可以进一步进行设计,并创建一个基本视图模型类,该类不仅可以用于PresentationOrders,还可以用于任何其他类:

public class BaseViewModel
{
    // Application properties
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }
}

现在,我们可以像这样简化PresentationOrderVM:

public class PresentationOrderVM : BaseViewModel
{
    // Business properties
    public PresentationOrder Order { get; set; }
}

public class PresentationOrderVM : BaseViewModel
{
    // Business properties
    public List<PresentationOrder> Orders { get; set; }
}

通过使它通用,可以使BaseViewModel更加可重用:

public class BaseViewModel<T>
{
    // Application properties
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }

    // Business property
    public T BusinessObject { get; set; }
}

现在,我们的实现很轻松:

public class PresentationOrderVM : BaseViewModel<PresentationOrder>
{
    // done!
}

public class PresentationOrderVM : BaseViewModel<List<PresentationOrder>>
{
    // done!
}

2
山姆,谢谢!这帮助我完全掌握了一个多方面的实体:View-Model。我是一名正在学习MVC架构的大学生,这阐明了开发人员可以使用的许多功能。如果可以的话,我会在你的答案旁边加一个星号。
Chef_Code

1
@Sam '视图模型通常包含与表示模型和DTO相同的属性,因此,它们常常彼此混淆。这是否意味着它们通常代替表示模型使用,还是要包含表示模型/ dto?
亚历山大·德克

2
@AlexanderDerck它们用于不同的目的。它们彼此混淆(错误)。不,您通常不会使用pres模型代替视图模型。更常见的是VM“包含”表示模型,即 MyViewModel<MyPresModel>
Sam

2
@Sam假设模型对象是活动对象,例如nhibernate模型。.因此,通过使用BusinessObject,我们不是将模型/活动对象直接暴露给视图吗?即可以使用业务对象直接修改数据库状态吗?另外,嵌套视图模型又如何呢?那将需要多个业务对象属性,对吗?
穆罕默德·阿里

22

如果您具有特定于视图的属性,而与数据库/服务/数据存储不相关,那么使用ViewModels是一个好习惯。假设您要保留一个或多个基于DB字段的复选框,但DB字段本身不是布尔值。尽管可以在模型本身中创建这些属性,并使它们对绑定数据隐藏起来,但您可能不希望根据此类字段和事务的数量来使模型混乱。

如果特定于视图的数据和/或转换太少,则可以使用模型本身


19

我没有阅读所有文章,但是每个答案似乎都缺少一个真正帮助我“理解”的概念。

如果Model类似于数据库Table,则ViewModel类似于数据库View -视图通常或者返回少量的数据从一个表,或者,复台从多个表(连接)数据的。

我发现自己使用ViewModels将信息传递到视图/表单中,然后在表单回发给控制器时将数据传输到有效的Model中-这对于存储Lists(IEnumerable)也非常方便。


11

MVC没有视图模型:它具有模型,视图和控制器。视图模型是MVVM(模型-视图-视图模型)的一部分。MVVM源自Presentation Model,并在WPF中普及。MVVM中也应该有一个模型,但是大多数人完全错过了该模式的要点,他们只会有一个视图和一个视图模型。MVC中的模型类似于MVVM中的模型。

在MVC中,该过程分为3个不同的职责:

  • View负责将数据呈现给用户
  • 控制器负责页面流
  • 模型负责业务逻辑

MVC不太适合Web应用程序。这是Smalltalk引入的用于创建桌面应用程序的模式。Web环境的行为完全不同。从桌面开发中复制一个已有40年历史的概念并将其粘贴到Web环境中没有多大意义。但是,许多人认为这是可以的,因为他们的应用程序会编译并返回正确的值。我认为,这还不足以宣布某种设计选择可以。

Web应用程序中的模型示例可以是:

public class LoginModel
{
    private readonly AuthenticationService authentication;

    public LoginModel(AuthenticationService authentication)
    {
        this.authentication = authentication;
    }

    public bool Login()
    {
        return authentication.Login(Username, Password);
    }

    public string Username { get; set; }
    public string Password { get; set; }
}

控制器可以像这样使用它:

public class LoginController
{
    [HttpPost]
    public ActionResult Login(LoginModel model)
    {
        bool success = model.Login();

        if (success)
        {
            return new RedirectResult("/dashboard");
        }
        else
        {
            TempData["message"] = "Invalid username and/or password";
            return new RedirectResult("/login");
        }
    }
}

您的控制器方法和模型将很小,易于测试并且很重要。


感谢您对MVVM架构的了解,但是为什么MVC不能正常运行?您的推理是有问题的,并且怀疑会偏favor。当然,我对MVVM一无所知,但是如果像MVC这样的体系结构可以模仿这种行为而不必编写5万行代码,那有什么大不了的呢?
Chef_Code

@Chef_Code:毫无疑问或偏favor:只需阅读有关MVC的原始论文即可。回到源头要比盲目跟随牧群毫无疑问(又名“最佳实践”)要好得多。MVC用于更小的单位:例如,屏幕上的按钮由模型,视图和控制器组成。在Web-MVC中,整个页面都有一个控制器,一个模型和一个视图。假定模型和视图已连接,因此模型中的更改会立即反映在视图中,反之亦然。模仿是很大的事情。架构不应该欺骗开发人员。
Jeroen

1
@jeroen MVC的首字母缩写已被盗用。是的,MVC没有VM,但也没有存储库或服务层,并且这些对象在网站中得到了广泛使用。我相信OP正在问“如何在MVC中引入和使用VM”。在MVC的新含义中,模型不是业务逻辑所属的地方。业务逻辑属于使用MVC或MVVM的Web或桌面应用程序的服务层。术语模型描述了传递到服务层或从服务层传递的业务对象。这些定义与MVC的原始描述有很大不同。
山姆

1
@Sam并非网站的所有内容都可以称为MVC的一部分。MVC没有新的含义。这里有正确的含义和“人们与MVC完全无关的事物”的含义。说模型负责业务逻辑,与模型中编码的业务逻辑不同。大多数时候,模型充当应用程序的基础。
Jeroen

我在Microsoft MVC中看到的主要缺陷是使用View锁定模型。这本身违背了过去20年来N-Tier设计中进行的所有分离的全部目的。他们浪费了我们的时间,迫使我们在2002年使用“ WebForms”,这是另一个基于桌面的模型,被应用到Web World中。现在,他们已经抛弃了这一点,但又在这个针对Web开发人员的新范式上悬挂了另一个桌面模型。同时,Google和其他公司正在建立将所有要素分开的巨型客户端模型。我认为1998年的旧ASP VBScript是他们最真实的Web开发系统。
Stokely'7

11

视图模型a是一个简单的类,可以包含多个类属性。我们使用它来继承所有必需的属性,例如,我有两个类Student和Subject

Public class Student
{
public int Id {get; set;}
public string Name {get; set;}
}  
Public class Subject
{
public int SubjectID {get; set;}
public string SubjectName {get; set;}
}

现在,我们想在“视图”中显示记录学生的姓名和主题的姓名(在MVC中),但是不可能添加多个类,例如:

 @model ProjectName.Model.Student  
 @model ProjectName.Model.Subject

上面的代码将引发错误...

现在,我们创建一个类,并可以为其指定任何名称,但是这种格式“ XyzViewModel”将使其更易于理解。它是继承的概念。现在,我们使用以下名称创建第三个类:

public class StudentViewModel:Subject
{
public int ID {get; set;}
public string Name {get; set;}
}

现在我们在View中使用这个ViewModel

@model ProjectName.Model.StudentViewModel

现在,我们可以访问View中的StudentViewModel和继承的类的所有属性。


10

有很多重要的例子,让我以清晰明了的方式进行说明。

ViewModel =创建用于服务视图的模型。

ASP.NET MVC视图不能有多个模型,因此如果我们需要在视图中显示多个模型的属性,则不可能。ViewModel用于此目的。

View Model是一个模型类,只能包含视图所需的那些属性。它还可以包含数据库的多个实体(表)中的属性。顾名思义,该模型是针对View需求创建的。

以下是视图模型的几个示例

  • 要从视图页面中的多个实体中列出数据–我们可以创建一个View模型,并拥有要为其列出数据的所有实体的属性。加入这些数据库实体并设置View模型属性,然后返回到View以一种表格形式显示不同实体的数据
  • 视图模型可能仅定义视图所需的单个实体的特定字段。

ViewModel还可以用于将记录插入并更新到多个实体中,但是ViewModel的主要用途是将来自多个实体(模型)的列显示到单个视图中。

创建ViewModel的方法与创建Model的方法相同,为Viewmodel创建视图的方法与为Model创建视图的方法相同。

这是一个小例子 使用ViewModel List数据

希望这会有用。


6

ViewModel是一种解决方法,可修补MVC框架在概念上的笨拙性。它表示3层模型-视图-控制器体系结构中的第4层。当Model(域模型)不适用于View(对于View而言太大(大于2-3个字段))时,我们创建较小的ViewModel以将其传递给View。


1

视图模型是数据的概念模型。它的用途是例如获取子集或合并来自不同表的数据。

您可能只需要特定的属性,因此这使您仅可以加载那些属性,而不必加载其他不必要的属性


1
  • ViewModel包含视图中表示的字段(用于LabelFor,EditorFor,DisplayFor帮助器)
  • ViewModel可以具有使用数据注释或IDataErrorInfo的特定验证规则。
  • ViewModel可以具有来自不同数据模型或数据源的多个实体或对象。

设计ViewModel

public class UserLoginViewModel 
{ 
[Required(ErrorMessage = "Please enter your username")] 
[Display(Name = "User Name")]
[MaxLength(50)]
public string UserName { get; set; }
 [Required(ErrorMessage = "Please enter your password")]
 [Display(Name = "Password")]
 [MaxLength(50)]
 public string Password { get; set; } 
} 

在视图中呈现视图模型

@model MyModels.UserLoginViewModel 
@{
 ViewBag.Title = "User Login";
 Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm())
{
<div class="editor-label">
 @Html.LabelFor(m => m.UserName)
</div>
<div class="editor-field">
 @Html.TextBoxFor(m => m.UserName)
 @Html.ValidationMessageFor(m => m.UserName)
</div>
<div class="editor-label">
 @Html.LabelFor(m => m.Password)
</div>
<div class="editor-field">
 @Html.PasswordFor(m => m.Password)
 @Html.ValidationMessageFor(m => m.Password)
</div>
<p>
 <input type="submit" value="Log In" />
</p>
</div>
}

采取行动

public ActionResult Login()
{ 
return View();
}
[HttpPost]
public ActionResult Login(UserLoginViewModel user)
{
// To acces data using LINQ
DataClassesDataContext mobjentity = new DataClassesDataContext();
 if (ModelState.IsValid) 
{ 
try
 {
 var q = mobjentity.tblUsers.Where(m => m.UserName == user.UserName && m.Password == user.Password).ToList(); 
 if (q.Count > 0) 
 { 
 return RedirectToAction("MyAccount");
 }
 else
 {
 ModelState.AddModelError("", "The user name or password provided is incorrect.");
 }
 }
 catch (Exception ex)
 {
 } 
 } 
 return View(user);
} 
  1. 在ViewModel中,仅将要显示的字段/数据放在视图/页面上。
  2. 由于视图代表了ViewModel的属性,因此易于呈现和维护。
  3. 当ViewModel变得更复杂时,请使用映射器。

1

View Model是可用于在View上呈现数据的类。假设您有两个实体Place和PlaceCategory,并且想使用一个模型从两个实体访问数据,然后我们使用ViewModel。

  public class Place
    {
       public int PlaceId { get; set; }
        public string PlaceName { get; set; }
        public string Latitude { get; set; }
        public string Longitude { get; set; }
        public string BestTime { get; set; }
    }
    public class Category
    {
        public int ID { get; set; }
        public int? PlaceId { get; set; }
        public string PlaceCategoryName { get; set; }
        public string PlaceCategoryType { get; set; }
    }
    public class PlaceCategoryviewModel
    {
        public string PlaceName { get; set; }
        public string BestTime { get; set; }
        public string PlaceCategoryName { get; set; }
        public string PlaceCategoryType { get; set; }
    }

因此,在上面的示例中,Place和Category是两个不同的实体,而PlaceCategory viewmodel是可以在View上使用的ViewModel。


您的示例不清楚。上面所说的是ViewModel将数据连接到其视图。如果您查看BlipAjax中的ViewModels,则会看到非常适合的类。
Herman Van Der Blom

0

如果您想研究如何使用ViewModels设置“基线” Web应用程序的代码,我建议您在GitHub上下载此代码:https : //github.com/ajsaulsberry/BlipAjax。我开发了大型企业应用程序。当您执行此操作时,设置一个好的架构来处理所有这些“ ViewModel”功能会遇到问题。我认为从BlipAjax开始,您将有一个很好的“基线”。它只是一个简单的网站,但简单易用。我喜欢他们使用英语指出应用程序中真正需要的方式。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.