【问题标题】:MVC and Entity Framework Html.DisplayNameFor with Composite ViewModelMVC 和实体框架 Html.DisplayNameFor 与复合 ViewModel
【发布时间】:2013-04-05 06:55:45
【问题描述】:

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

我创建了一个名为 TestSitesController 的控制器,它是从我的实体框架模型(生成读/写操作和视图的模板)中的“站点”模型类自动生成的。我唯一修改的是在 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<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);
}

然后我复制了 Index.cshtml 并将其命名为 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”而不是使用“Web Page Title”(如在中的数据注释的 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


    【解决方案1】:

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

    第一个问题为了在数据注释中使用显示属性,必须添加 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 表格标签?我想这是另一个日期的另一个问题。

    【讨论】:

    【解决方案2】:

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

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

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

    祝你好运!

    【讨论】:

    • 不要调用@Html.DisplayNameFor(model => model.WebPageTitle),而是尝试使用@Html.DisplayFor(model => model.WebPageTitle)。我两个都用。 DisplayNameFor 应该给我在 [Display(Name = "Web Page Title")] 数据注释中使用的友好标签。 DisplayFor 工作正常,并为我提供了 model.WebPageTitle 的值。这段代码工作正常,除了 DisplayNameFor 给我返回变量名“WebPageTitle”而不是“网页标题”。我根本无法让 DisplayNameFor 为站点的 IEnumerable 工作
    • 啊,明白了。我通常最终使用带有自定义显示的标签助手来处理这类事情。 @Html.LabelFor(model =&gt; model.WebPageTitle, "Web Page Title")
    • 如果我每次使用 LabelFor 时都输入“网页标题”,这适用于 model.WebPateTitle,但我仍然不知道如何让它使用通过 Data Annotation 声明的值[显示(名称=“网页标题”)]。我希望能够在一个地方轻松地改变它……这是使用 Display 属性和 Data Annotations 的全部意义所在。知道如何让它工作吗?同样,这也适用于站点的 IEnumerable。有趣的是,它可以与生成的代码一起使用,但当我将它放在复合视图模型中时却不行。
    • 对于共享模板和部分视图,我在学习时尽量保持简单,目前认为最简单的方法是将两个模型放在一个“复合视图模型”中,这种做法在 MVVM 世界中很常见。
    • 更新...当我添加了一个get;放;默认访问器方法 @Html.DisplayNameFor(model => model.WebPageTitle) 的问题正常工作。我将更多地使用 IEnumerable 属性,看看我是否不能让它工作。我更改了 [Required, Display(Name = "Web Page Title")] public string WebPageTitle;到[必需,显示(名称=“网页标题”)]公共字符串WebPageTitle {get;放; } 这解决了 DisplayNameFor 问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 2010-09-25
    • 2013-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多