ASP.NET MVC 3 - 部分与显示模板与编辑器模板

Posted

技术标签:

【中文标题】ASP.NET MVC 3 - 部分与显示模板与编辑器模板【英文标题】:ASP.NET MVC 3 - Partial vs Display Template vs Editor Template 【发布时间】:2011-06-29 14:01:06 【问题描述】:

所以,标题应该说明一切。

要在 ASP.NET MVC 中创建可重用组件,我们有 3 个选项(可能是我没有提到的其他选项):

局部视图:

@html.Partial(Model.Foo, "SomePartial")

自定义编辑器模板:

@Html.EditorFor(model => model.Foo)

自定义显示模板:

@Html.DisplayFor(model => model.Foo)

就实际的 View/HTML 而言,所有三个实现都是相同的:

@model WebApplications.Models.FooObject

<!-- Bunch of HTML -->

那么,我的问题是 - 您何时/如何决定使用这三个中的哪一个?

我真正想要的是在创建之前要问自己的问题列表,这些问题的答案可用于决定使用哪个模板。

这是我发现使用 EditorFor/DisplayFor 更好的两件事:

    他们在渲染 HTML 助手时尊重模型层次结构(例如,如果您的“Foo”模型上有一个“Bar”对象,“Bar”的 HTML 元素将使用“Foo.Bar.ElementName”渲染,而部分将具有“ElementName”)。

    更健壮,例如,如果您的 ViewModel 中有 List&lt;T&gt; 的某些东西,您可以使用 @Html.DisplayFor(model =&gt; model.CollectionOfFoo),并且 MVC 足够聪明,可以看到它是一个集合并为每个项目呈现单个显示 (而 Partial 则需要显式的 for 循环)。

我还听说 DisplayFor 渲染了一个“只读”模板,但我不明白 - 我不能在上面扔一个表单吗?

谁能告诉我一些其他的原因?有没有比较这三者的列表/文章?

【问题讨论】:

编辑器和显示模板背后的概念在 asp.net mvc 2 的文档中明确定义。模板是遵守特定约定的部分。使模板比旧的部分更好或更差的情况几乎完全取决于该约定是否值得在您的应用程序中遵守。 【参考方案1】:

EditorFor vs DisplayFor 很简单。这些方法的语义是生成编辑/插入和显示/只读视图(分别)。在显示数据时使用DisplayFor(即当您生成包含模型值的 div 和 span 时)。在编辑/插入数据时使用EditorFor(即当您在表单中生成输入标签时)。

以上方法都是以模型为中心的。这意味着它们将考虑模型元数据(例如,您可以使用 [UIHintAttribute][DisplayAttribute] 注释模型类,这将影响选择哪个模板来生成模型的 UI。它们通常也用于数据模型(即表示数据库中行的模型等)

另一方面,Partial 以视图为中心,因为您最关心的是选择正确的局部视图。视图不一定需要模型才能正常运行。它可以只有一组通用的标记,可以在整个站点中重复使用。当然,很多时候你想要影响这个局部的行为,在这种情况下你可能想要传入一个合适的视图模型。

你没有问过@Html.Action,这里也值得一提。您可以将其视为Partial 的更强大版本,因为它执行控制器子操作,然后呈现视图(通常是局部视图)。这很重要,因为子操作可以执行不属于局部视图的附加业务逻辑。例如,它可以表示购物车组件。使用它的原因是避免在应用程序的每个控制器中执行与购物车相关的工作。

最终的选择取决于您在应用程序中建模的是什么。还请记住,您可以混合搭配。例如,您可以有一个调用 EditorFor 助手的局部视图。这实际上取决于您的应用程序是什么以及如何将其分解以鼓励最大程度地重用代码,同时避免重复。

【讨论】:

这是一个很好的答案,正是我想要的。实际上,我指望你会来回答这个事实。 :) 谢谢马辛。 如何使用注解为单个属性指定显示模板和编辑器模板? @stormwild 要么使用约定并在模板相关的模型 (/Views/DisplayTemplates/MyModel.cshtml) 之后命名模板,要么使用 UIHint 注释显式强制它。 对于创建可重用的“注册用户”向导有什么建议?如果可能,我想在单独的程序集中创建这些视图(和控制器)。 Aka,一种在多个团队之间重新分配这些可重复使用的 mvc 表单/控制器的方法。 (我们创建了一种处理用户/存储(webapi 服务)的单一方式......但是每个团队都在创建自己的 mvc 页面: 您将这些模板存储在哪里?我需要将它们存储在 Shared/EditorTemplates 中还是可以将它们直接存储在当前控制器文件夹中(当我只需要它们时)?【参考方案2】:

您当然可以自定义DisplayFor 以显示可编辑的表单。但惯例是 DisplayForreadonlyEditorFor 是用于编辑。遵守约定将确保无论您向DisplayFor 传递什么,它都会做相同类型的事情。

【讨论】:

我认为对于何时应该使用显示模板和编辑器模板没有任何疑问。真正的问题似乎是何时应该使用模板与部分。您的回答完全忽略了这一点。 @Joshua - 我认为有一些问题:“我也听说 DisplayFor 呈现一个“只读”模板,但我不明白 - 我不能抛出一个表格在那里?”【参考方案3】:

只是为了给我 2c 的价值,我们的项目使用带有几个 jQuery 选项卡的局部视图,每个选项卡都使用自己的局部视图呈现其字段。这一直很好,直到我们添加了一些选项卡共享一些公共字段的功能。我们的第一种方法是使用这些公共字段创建另一个局部视图,但是当使用 EditorFor 和 DropDownListFor 呈现字段和下拉菜单时,这变得非常笨拙。为了获得唯一的 id 和名称,我们必须根据渲染它的父部分视图来渲染带有前缀的字段:

    <div id="div-@(idPrefix)2" class="toHide-@(idPrefix)" style="display:none">
    <fieldset>
        <label for="@(idPrefix).Frequency">Frequency<span style="color: #660000;"> *</span></label>

        <input name="@(idPrefix).Frequency"
               id="@(idPrefix)_Frequency"
               style="width: 50%;"
               type="text"
               value="@(defaultTimePoint.Frequency)"
               data-bind="value: viewState.@(viewStatePrefix).RecurringTimepoints.Frequency"
               data-val="true"
               data-val-required="The Frequency field is required."
               data-val-number="The field Frequency must be a number."
               data-val-range-min="1"
               data-val-range-max="24"
               data-val-range="The field Frequency must be between 1 and 24."
               data-val-ignore="true"/>

        @Html.ValidationMessage(idPrefix + ".Frequency")

        ... etc

    </fieldset>
</div>

这变得非常难看,所以我们决定改用编辑器模板,这样更简洁。我们添加了一个带有公共字段的新视图模型,添加了一个匹配的编辑器模板,并使用来自不同父视图的编辑器模板渲染了字段。编辑器模板正确呈现 id 和名称。

简而言之,我们使用编辑器模板的一个令人信服的原因是需要在多个选项卡中呈现一些公共字段。部分视图不是为此而设计的,但编辑器模板可以完美地处理场景。

【讨论】:

我在使用选项卡时遇到了类似的问题,最终使用了 Steve Sanderson 的 BeginCollectionItem,它为您生成了唯一的控件 ID:blog.stevensanderson.com/2010/01/28/…【参考方案4】:

在以下情况下使用_partial 查看方法:

    查看中心逻辑 仅在此视图中保留所有与_partial 视图相关的 HTML。在模板方法中,您必须在模板视图之外保留一些 HTML,例如“主标题或任何外部边框/设置。 想要使用 URL.Action("action","controller") 以逻辑(来自控制器)呈现部分视图。

使用模板的原因:

    想要删除ForEach(Iterator)。模板足以将模型识别为列表类型。它会自动完成。 以模型为中心的逻辑。如果在同一 displayfor Template 文件夹中找到多个视图,则渲染将取决于 Passed Model。

【讨论】:

【参考方案5】:

到目前为止还没有提到的另一个区别是局部视图不会添加模型前缀,而模板会添加 Here 是问题

【讨论】:

以上是关于ASP.NET MVC 3 - 部分与显示模板与编辑器模板的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC 与 XSL

asp.net MVC 路由

[Asp.Net Core]MVC_Razor布局

[Asp.Net Core]MVC_Razor布局

asp.net mvc 中的部分视图

ASP.NET中MVC的理解