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


303

因此,标题应能说明一切。

要在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更好的两件事:

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

  2. 更加健壮,例如,如果List<T>ViewModel中包含a 之类的东西,则可以使用@Html.DisplayFor(model => model.CollectionOfFoo),并且MVC足够聪明,可以看到它是一个集合,并为每个项目呈现单个显示(与Partial相反,这需要显式环)。

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

有人可以告诉我其他原因吗?是否有清单/文章比较这三个地方?


asp.net mvc 2的文档中明确定义了编辑器和显示模板的概念。模板是遵守特定约定的部分。使模板比旧部分更好或更糟的情况几乎严格取决于约定是否值得在您的应用程序中遵循。
尼克·拉森,

Answers:


301

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

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

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

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

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


4
这是一个很好的答案,正是我想要的。实际上,我是在依靠您来回答这个事实。:)谢谢marcin。
RPM1984

如何使用注释为单个属性指定显示模板和编辑器模板?
2011年

3
@stormwild使用约定并在与它们相关的模型之后命名您的模板(/Views/DisplayTemplates/MyModel.cshtml),或使用UIHint注释明确强制使用模板。
汤姆·韦森

对于创建可重用的“注册用户”向导有何建议?如果可能,我想在单独的程序集中创建这些视图(和控制器)。又名,一种在多个团队之间重新分配这些可重用的MVC表单/控制器的方法。(我们已经创建了处理用户/存储(的WebAPI服务)的单一方式......但每个团队正在开发自己的MVC网页:<谢谢。
granadaCoder

您将这些模板存储在哪里?我需要将它们存储在Shared / EditorTemplates中还是可以将它们直接存储在当前控制器文件夹中(当我仅在此处需要它们时)?
桑索斯

15

您当然可以自定义DisplayFor显示可编辑的表单。但是约定是DisplayFor必须存在的,readonly也是EditorFor要进行编辑的。遵守约定将确保无论您传入什么内容DisplayFor,它都会做相同类型的事情。


2
对于何时应该使用显示模板还是编辑器模板,我不存在任何疑问。真正的问题似乎是什么时候应该使用模板而不是局部对象。您的答案完全错过了这一点。
约书亚·海斯

19
@Joshua-我认为有一个问题:“我也听说DisplayFor呈现了一个“只读”模板,但我不明白-我不能在上面扔表格吗?”
罗伯特·利维

13

仅仅为了给我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和名称。

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


1
我在使用标签时遇到了类似的问题,最终使用了史蒂夫·桑德森(Steve Sanderson)的BeginCollectionItem为您生成唯一的控件ID:blog.stevensanderson.com/2010/01/28/…– 2013
威尔基

1

在以下情况下使用_partial视图方法:

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

使用模板的原因:

  1. 要删除ForEach(Iterator)。模板足以将Model识别为列表类型。它将自动执行。
  2. 模型中心逻辑。如果在同一display模板文件夹中找到多个视图,则渲染将取决于“通过的模型”。

1

到目前为止,尚未提及的另一个区别是,局部视图不会在模板执行操作时添加模型前缀, 是问题所在

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.