ASP.NET MVC 和实体框架 Html.DisplayNameFor 与复合 ViewModel

问题描述 投票:0回答:2

我对使用 WPF/Silverlight 的 MVVM 相当满意,但这是我第一次尝试 ASP.NET MVC Web 应用程序...仅供参考。

我创建了一个名为

TestSitesController
的控制器,它是从我的实体框架模型中的“Site”模型类(生成读/写操作和视图的模板)自动生成的。 我唯一修改的是在 3 个地方,某些方法有一个默认参数 Guid id = null。 我刚刚摆脱了“= null”,一切正常。

这是我更改的示例

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

这已更改为

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

站点模型没有什么特别的 SiteId、缩写和 DisplayName…对于这个问题,尝试使其尽可能简单。好的,我运行网站并转到 htpp://.../TestSites/,一切正常。

我注意到我的所有视图(创建、删除、详细信息和编辑)都使用

@model MVCWeb.MyEntities.Site
,目前我完全可以接受;但在
Index.cshtml
视图中我注意到它使用的是

@model IEnumerable<MVCWeb.MyEntities.Site>

这对于生成的模板来说效果很好,但我想使用“复合视图模型”,也许这就是我试图混合我的 MVVM 知识的地方,但如果可能的话,我会坚持使用它。 在我看来,复合视图模型只是一个特定于由 1 个或多个实体模型以及 SelectedSiteId 等附加属性组成的视图的模型。

所以我创建了一个非常简单的视图模型,名为

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, IEnumerables, 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
以匹配我的新方法名称。我改变了

的顶行
@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”的变量名称,而不是使用“网页标题”,如

中数据注释的 Display 属性所示
[Display(Name = "Web Page Title")]
public string WebPageTitle;

另外,如果我在包含表头信息的 tr 部分中进行评论。 我一生都无法弄清楚要放入什么我已经尝试过 model.Sites.Abbreviation、model.Sites[0].Abbreviation 和各种其他组合,但出现错误。

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

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

c# asp.net-mvc-4 .net-4.5 razor-2
2个回答
23
投票

经过几个小时的折腾,我终于弄清楚了。

第一个问题,为了在数据注释中使用 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, IEnumerables, 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 表标签?我想这是另一个约会的另一个问题。


1
投票

我将尝试一下我新学到的 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 将自动选取这些模板。

祝你好运!

© www.soinside.com 2019 - 2024. All rights reserved.