2013-05-14 16 views
36

比方说,我有一个页面,允许用户的详细信息的编辑,所以我有一个视图模型是这样的:ASP.NET MVC - 究竟是如何使用视图模型

public class UserViewModel { 
    public string Username { get; set; } 
    public string Password { get; set; } 
    public int ManagerId { get; set; } 
    public string Category { get; set; } 
} 

所以我EditUser行动我能有这样的回传被模型绑定,然后我可以映射到域模型:

public ActionResult EditUser(UserViewModel user) { 
    ... 

然而,这显示表单的页面也需要细节,如经理和分类的列表提供下拉菜单供那些领域。它也可能在侧边栏中显示其他用户的列表,以便您可以在正在编辑的不同用户之间进行切换。

于是我有另一种看法型号:

public class ViewUserViewModel { 
    public UserViewModel EditingUser { get; set; } 
    public IEnumerable<SelectListItem> Managers { get; set; } 
    public IEnumerable<SelectListItem> Categories { get; set; } 
    public IEnumerable<SelectListItem> AllUsers { get; set; } 
} 

这是做了正确的方法是什么?他们都是视图模型吗?如果是这样,是否有我应该使用的命名约定,以便我可以区分类似模型的虚拟机和仅包含页面数据的虚拟机?

我有这个错误吗?

回答

20

我如何做到这一点的快捷方式:

  1. 为每个单独的ViewModel类窗体在页面上,然后我用PartialViews渲染这些类为@{Html.RenderPartial("PartialName", Model.PartialModel);}
  2. 如果页面包含html metas之类的东西,我为metas制作分隔类,并将其放在页面的部分。
  3. 休息例如“我应该把它放在分开的班级吗?”是你的判断。

因此,例如,你有页面有某种登录/注册栏或弹出任何。

public class SomePageViewModel 
{ 
    public RegisterBarVM Register { get; set; } 
    public LoginBarVM LoginBar { get; set; } 

    public MetasVM Metas { get; set; } 
    public string MaybePageTitle { get; set;} 
    public string MaybePageContent { get; set;} 

    [HiddenInput(DisplayValue = false)] 
    public int IdIfNeeded { get; set; } 

    public IEnumerable<SelectListItem> SomeItems {get; set;} 
    public string PickedItemId { get;set; } 
} 

public class RegisterBarVM 
{ 
    public string RegisterUsername {get;set;} 
    public string RegisterPassword {get;set;} 
    //... 
} 

public class LoginBarVM 
{ 
    public string LoginUserame {get;set;} 
    public string LoginPassword {get;set;} 
    //... 
} 

//cshtml 
@model yourClassesNamespace.SomePageViewModel 
@{ 
    Html.RenderPartial("LoginBar", Model.LoginBar); //form inside 
    Html.RenderPartial("RegisterBar", Model.RegisterBar); //form inside 

    using(Html.BeginForm()) 
    { 
     @Html.EditorFor(m => m.IdIfNeeded) 
     @Hmtl.EditorFor(m => m.MaybePageTitle) 
     @Hmtl.EditorFor(m => m.MaybePageContent) 

     @Hmtl.DropDownListFor(m => m.PickedItemId, new SelectList(Model.SomeItems)) 

     <input type="submit" value="Update" /> 
    } 
} 

@section Metas { 
    @{Html.RenderPartial("Meatas", Model.Metas} 
} 

关于编辑模板Brad Wilsons Blog,只是谷歌或查找有关显示/编辑模板和HtmlHelpers栈资源。它们对构建一致的网站非常有用。

9

我个人比较喜欢把页面所需的所有信息放在ViewModel中,因为这是ViewModel的目的 - 为View提供所有的数据。所以我的UserViewModel将包含Managers,CategoriesAllUsers的属性,并且在将ViewModel传递到视图之前,控制器将填充这些集合。

这实质上就是你所做的 - 它只是从等式中移除额外的ViewModel。

我也看到其他程序员使用ViewData将下拉列表发送到视图,但我不喜欢,因为ViewData不强类型,而ViewModel是。

93

“查看模型”只是一种模式。关于名称没有什么不可思议的,但是通常任何类别被传递给视图(无论是简单地显示数据还是用于表单提交的目的)都被称为“视图模型”,并且给出诸如FooViewModelFooVM这样的名称以指示它是“视图模型”模式的一部分。

我不想对你太过哲学,但我认为对游戏模式的一点参考将会有所帮助。 ASP.NET MVC显然足以鼓励MVC(模型 - 视图 - 控制器)架构模型。在MVC中,模型是所有应用程序的商业逻辑的容器。 Controller负责处理请求,获取模型,使用该模型呈现View并返回响应。这似乎是很多责任,但实际上框架处理幕后的大部分内容,所以控制器通常(而且应该)在代码上非常轻。他们负责将所有东西连接起来的最低限度的功能。最后,视图负责创建UI层,允许用户与模型中的数据进行交互。它不是而是负责数据本身,也不应该是这样(ViewData/ViewBag在这里是一个非常大的违规,至少和开发人员在实践中使用它的方式一样)。

所以,这意味着你的应用程序逻辑的大部分应该在你的模型中,通常这是一件好事。但是,由于该模型是应用程序数据的避风港,因此通常会保留在数据库或类似数据库中。这会产生一些利益冲突,因为您现在需要在应该保留哪些数据与仅存在用于显示目的的数据之间开始平衡操作。

这就是视图模型出现的地方。MVVM(模型 - 视图 - 视图模型)是一种与MVC有点平行的模式,它认识到单一模式到规则全部方法的固有问题。这里我不会详细讨论,因为MVC不使用这种模式。但是,大多数ASP.NET MVC开发人员已经选择了MVVM的View Model。你实际上最终得到的是由数据库支持的实体(传统模型),然后通常是代表该实体处于各种状态的许多不同视图模型。这允许您的模型包含与持久性相关的业务逻辑,而视图模型包含与显示,创建和更新模型相关的业务逻辑。

我已经走了一段路,但多空是你所做的完全可以接受的。事实上,这是很好的做法。根据应用程序的需要创建尽可能多的视图模型,并使用它们实际存储视图所需的数据和业务逻辑。 (这包括像SelectList既不控制器也不观点应该需要知道如何为下拉列表创建SelectList。)

+6

关于这个问题的最好解释。你应该把它放在博客上! +1 – 2014-02-04 16:51:19

+0

你已经提到模型应该负责应用程序的业务逻辑。通过业务,您可能意味着所有的数据准备,查询,过滤,投影一个模型到另一个模型,或者一个特定的ViewModel。然后这样准备好的ViewModel被控制器传递给View。你如何做到这一点?你如何设计模型来做生意?你是否将所有控制器方法移动到表示视图模型的类中?目前,我在控制器中有许多功能和“业务”,这些功能和操作完成所有的位和螺栓。谢谢 – Celdor 2015-07-31 10:29:47

+0

坦率地说,你不能在ASP.NET MVC中做到这一点。要真正理解我在说什么,请在Ruby on Rails中构建一个示例应用程序。 RoR非常严格地遵守MVC模式,您将会看到他们的模型到底有多少。另一方面,ASP.NET MVC只是松散地遵守MVC。你“模型”将是实体类,视图模型以及类似存储库或服务的某种组合。你应该尽量保持你的控制器精简,你不能将所有逻辑移动到一个类中。 – 2015-07-31 18:19:59