MVC和实体框架Html.DisplayNameFor与复合视图模型

本文关键字:复合 视图 模型 DisplayNameFor Html 实体 框架 MVC | 更新日期: 2023-09-27 18:08:47

我对使用WPF/Silverlight的MVVM相当满意,但这是我第一次尝试MVC Web应用程序…只是为了我的背景。

我已经创建了一个名为TestSitesController的控制器,它是从我的实体框架模型(生成读/写操作和视图的模板)中的"Site"模型类自动生成的。我唯一修改的是在3个地方有一个默认参数Guid id = null的一些方法。我只是去掉了" = null ",一切正常。下面是我修改

的一个例子
public ActionResult Delete(Guid id = null)
{
    //....
}

修改为

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

站点模型没有什么特别的SiteId,缩写和DisplayName…对于这个问题,尽量保持简单。所以我运行这个网站,转到https://…/TestSites/,一切都运行良好。

我注意到我所有的视图(创建,删除,详细信息和编辑)都使用@model MVCWeb.MyEntities.Site,我现在很好;而是在索引中。cshtml视图,我注意到它使用了

@model IEnumerable<MVCWeb.MyEntities.Site>

这对于生成的模板来说很好,但我想使用"复合视图模型",也许这就是我试图混合我的MVVM知识的地方,但如果可能的话,我会坚持下去。在我看来,复合视图模型只是一个特定于由1个或多个实体模型以及附加属性(如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<MVCWeb.MyEntities.Site> 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);
}

然后我制作了索引的副本。并将其命名为IndexWithModel。cshtml来匹配我的新ActionResult方法名称。我改变了

的首行
@model IEnumerable<MVCWeb.MyEntities.Site>

@model MVCWeb.Models.TestSitesViewModel

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

@Html.DisplayNameFor(model => model.WebPageTitle)
&nbsp;
@Html.DisplayFor(model => model.WebPageTitle)
<br />

改变

@foreach (var item in Model) {

@foreach (var item in Model.Sites) {

并注释掉包含所有表头的tr部分。除了@Html之外,一切都很完美。DisplayNameFor显示的是"WebPageTitle"的变量名,而不是像

中Data Annotation的Display属性所表示的那样使用"WebPageTitle"。
[Display(Name = "Web Page Title")]
public string WebPageTitle;

同样,如果我在tr部分中注释回包含表头信息。我这辈子都不知道该放什么进去,我试过模型网站。缩写,model.Sites[0]。缩写,和各种其他组合,但得到错误。

<tr>
    <th>
        @Html.DisplayNameFor(model => model.Abbreviation)
    </th>
    <th>
        @Html.DisplayNameFor(model => model.DisplayName)
    </th>
    <th></th>
</tr>

我应该用什么呢?我不太确定为什么model.Sites. acronym不起作用,因为Sites与原始Index.cshtml

MVC和实体框架Html.DisplayNameFor与复合视图模型

中用作模型的类型完全相同

折腾了几个小时,我终于弄明白了。

第一个问题为了在数据注释中使用Display属性,必须添加get和set访问方法,即使它们只是默认的。我认为这是因为它们只能处理属性,而不能处理类的公共数据成员。下面是获取

的代码
@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<MVCWeb.MyEntities.Site> Sites;
    //Other Entities, IEnumberables, or properties go here
    //Not important for this example
}

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

访问属性。
@{var headerMetadata = Model.Sites.FirstOrDefault();}
<tr>
    <th>            
        @Html.DisplayNameFor(model => headerMetadata.Abbreviation)
    </th>
    <th>
        @Html.DisplayNameFor(model => headerMetadata.DisplayName)
    </th>
    ...

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

我将用我新学的MVVM ASP尝试一下。. NET MVC经验

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

查看ASP共享模板。净MVC。您可以在/Views/Shared/EditorTemplates/Site.cshtml/Views/Shared/DisplayTemplates/Site.cshtml为DisplayFor/EditorFor助手设置自定义模板或部分。ASP。. NET MVC在使用DisplayFor和EditorFor渲染Site对象时将自动选择这些模板。

祝你好运!