具有复合ViewModel的MVC和entity frameworkHtml.DisplayNameFor

我对使用WPF / Silverlight的MVVM非常熟悉,但这是我第一次尝试使用MVC Web应用程序…这只是我的背景。

我创建了一个名为TestSitesController的控制器,它是从我的entity framework模型(生成读/写操作和视图的模板)中的“站点”模型类自动生成的。 我修改的唯一的东西是3个点,对于某些方法,有一个默认参数Guid id = null。 我摆脱了“= null”一切正常。 这是我改变的一个例子

public ActionResult Delete(Guid id = null) { //.... } 

这被改为

 public ActionResult Delete(Guid id) { //.... } 

Site模型没有什么特别的SiteId,Abbreviation和DisplayName ……试图让这个问题尽可能简单。 好的,所以我运行网站并转到htpp://…/TestSites/,一切都很完美。

我注意到我的所有视图(创建,删除,详细信息和编辑)都使用了@model MVCWeb.MyEntities.Site,我现在完全可以使用它; 但在Index.cshtml视图中,我注意到它正在使用

 @model IEnumerable 

这适用于生成的模板,但我想使用“复合视图模型”,也许这就是我试图混合我的MVVM知识,但如果可能的话就会坚持下去。 在我看来,复合视图模型只是一个特定于一个视图的模型,该视图由一个或多个实体模型以及其他属性(如SelectedSiteId等)组成。

所以我创建了一个非常简单的ViewModel,名为TestSitesViewModel

 public class TestSitesViewModel { //Eventually this will be added to a base ViewModel to get rid //of the ViewBag dependencies [Display(Name = "Web Page Title")] public string WebPageTitle; public IEnumerable Sites; //Other Entities, IEnumberables, or properties go here //Not important for this example } 

然后在我的控制器中添加了一个名为IndexWithViewModel的动作方法

 public ActionResult IndexWithViewModel() { var vm = new TestSitesViewModel(); vm.WebPageTitle = "Sites With Composite View Model"; vm.Sites = db.Sites.ToList(); return View(vm); } 

然后,我创建了一个Index.cshtml的副本,并将其命名为IndexWithModel.cshtml以匹配我的新ActionResult方法名称。 我改变了顶线

 @model IEnumerable 

 @model MVCWeb.Models.TestSitesViewModel 

我在表部分之前添加了这个来测试DisplayNameFor和DisplayFor

 @Html.DisplayNameFor(model => model.WebPageTitle)   @Html.DisplayFor(model => model.WebPageTitle) 

改变了

 @foreach (var item in Model) { 

 @foreach (var item in Model.Sites) { 

并注释掉了包含所有表头的tr部分。 除了@ Html.DisplayNameFor显示变量名称“WebPageTitle”而不是使用“Web页面标题”(如数据注释的Display属性中所示)之外,一切都运行良好。

 [Display(Name = "Web Page Title")] public string WebPageTitle; 

此外,如果我在包含表头信息的tr部分中回复。 我不能为我的生活弄清楚放入什么我已经尝试过model.Sites.Abbreviation,model.Sites [0]。缩写,以及各种其他组合但是得到错误。

   @Html.DisplayNameFor(model => model.Abbreviation)   @Html.DisplayNameFor(model => model.DisplayName)    

那我应该在那里使用什么? 我不太清楚为什么model.Sites.Abbreviation不起作用,因为Sites是与原始Index.cshtml中的模型完全相同的类型

经过几个小时的捣乱,我终于弄明白了。

第一个问题是,为了在Data Anotations中使用Display arrtibute,必须添加get和set acessor方法,即使它们只是默认方法。 我假设这是因为它们只能用于属性,而不能用于类的公共数据成员。 这是得到的代码

 @Html.DisplayNameFor(model => model.WebPageTitle) 

工作正常

 public class TestSitesViewModel { //Eventually this will be added to a base ViewModel to get rid of //the ViewBag dependencies [Display(Name = "Web Page Title")] public string WebPageTitle { get; set; } //PUBLIC DATA MEMBER WON'T WORK //IT NEEDS TO BE PROPERTY AS DECLARED ABOVE //public string WebPageTitle; public IEnumerable Sites; //Other Entities, IEnumberables, or properties go here //Not important for this example } 

第二部分问题是在IEnumerable变量中访问元数据。 我声明了名为headerMetadata的临时变量并使用它而不是尝试通过IEnumerable访问属性

 @{var headerMetadata = Model.Sites.FirstOrDefault();}   @Html.DisplayNameFor(model => headerMetadata.Abbreviation)   @Html.DisplayNameFor(model => headerMetadata.DisplayName)  ... 

这确实提出了headerMetadata变量何时超出范围的问题? 它可用于整个视图还是仅限于html表标签? 我想这是另一个约会的另一个问题。

我将学习新学到的MVVM ASP.NET MVC经验。

而不是调用@Html.DisplayNameFor(model => model.WebPageTitle) ,尝试使用@Html.DisplayFor(model => model.WebPageTitle) 。 您似乎在IndexWithViewModel控制器中设置WebPageTitle值,该值应显示在您的视图中。

查看ASP.NET MVC的共享模板 。 您可以在/Views/Shared/EditorTemplates/Site.cshtml/Views/Shared/DisplayTemplates/Site.cshtml为DisplayFor / EditorFor帮助程序设置自定义模板或部分。 在使用DisplayFor和EditorFor呈现Site对象时,ASP.NET MVC将自动获取这些模板。

祝好运!