ASP.NET MVC 3 - Partial vs Display Template vs Editor Template ASP.NET MVC 3 - 部分视图、显示模板和编辑模板的区别

309

因此,标题应该说明问题。

在ASP.NET MVC中创建可重用组件有三个选项(可能还有其他未提及的选项):

局部视图:

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

自定义编辑器模板:

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

自定义显示模板:

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

就实际的视图/HTML而言,这三种实现是完全相同的:

@model WebApplications.Models.FooObject

<!-- Bunch of HTML -->

因此,我的问题是 - 在何时/如何决定使用这三个中的哪一个?

我真正想要的是一系列问题,可以在创建模板之前问自己,通过回答这些问题来决定使用哪个模板。

下面是我发现EditorFor/DisplayFor更好的两个方面:

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

  2. 更加强大,例如,如果您的ViewModel中有一个List<T>,则可以使用@Html.DisplayFor(model=>model.CollectionOfFoo),MVC足够智能,以便看到它是一个集合,并为每个项目渲染单个显示(而不是一个部分视图,它需要显式循环)。

我还听说DisplayFor呈现“只读”模板,但我不理解 - 我不能在那里放置一个表单吗?

有人可以告诉我其他原因吗?是否有比较这三者的列表或文章?


ASP.NET MVC 2的文档清晰地定义了编辑器和显示模板背后的概念。模板是部分视图,遵循特定的约定。使用模板是否比旧的部分视图更好或更差,几乎完全取决于在您的应用程序中是否值得遵守这种约定。 - Nick Larsen
5个回答

308

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

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

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

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

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


4
非常好的回答,正是我在寻找的。实际上我很期待你来回答这个问题。 :) 谢谢Marcin。 - RPM1984
你如何使用注解为单个属性指定显示模板和编辑模板? - stormwild
3
要么按照惯例,根据它们所关联的模型命名您的模板(例如/Views/DisplayTemplates/MyModel.cshtml),要么使用UIHint注释显式强制执行。 - Tom Wayson
有没有什么建议可以用来创建可重用的“注册用户”向导?如果可能的话,我想在单独的程序集中创建这些视图(和控制器)。也就是说,一种将这些可重用的MVC表单/控制器在多个团队之间重新分配的方法。(我们已经创建了一种处理用户/存储(WebAPI服务)的单一方式...但每个团队都在创建自己的MVC页面 :< )谢谢。 - granadaCoder
你把这些模板存储在哪里?我需要将它们存储在Shared/EditorTemplates中吗?还是可以直接将它们存储在当前控制器文件夹中(仅当我只需要它们在那里时)? - Santhos

15

你当然可以自定义DisplayFor以显示可编辑表单。但惯例是DisplayForreadonly,而EditorFor则用于编辑。坚持遵循惯例将确保无论您传递什么参数到DisplayFor,它都会执行相同类型的操作。


2
我认为关于何时应该使用显示模板和编辑器模板,实际上并没有任何疑问。真正的问题似乎是何时应该使用模板而不是部分视图。你的回答完全忽略了这一点。 - Joshua Hayes
19
@Joshua - 我想有人对此有疑问:"我也听说DisplayFor渲染一个“只读”模板,但是我不明白 - 我不能在上面放一个表单吗?" - Robert Levy

13

仅提供我的意见,我们的项目使用了一个带有多个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>

这看起来相当丑陋,因此我们决定改用Editor Templates,这样做会更加简洁明了。我们添加了一个新的View Model,其中包含一些共同的字段,同时添加了对应的Editor Template,并在不同的父级视图中使用Editor Template来渲染这些字段。Editor Template能够正确地呈现ID和名称。

因此,我们使用Editor Templates的一个令人信服的原因是需要在多个选项卡中呈现一些共同的字段。Partial views并不适合这种情况,但是Editor Templates完美地处理了这个问题。


1
我曾经在使用选项卡时遇到类似的问题,最终采用了Steve Sanderson的BeginCollectionItem解决方案,该方案可以为您生成唯一的控件ID:http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/ - Wilky

2
到目前为止还没有提到的另一个区别是,PartialView 不会添加模型前缀,而 Template 会。这里 是问题所在。

1

如果:

  1. 视图中心的逻辑
  2. 希望将所有与_partial相关的HTML都保留在此视图中。在模板方法中,您需要将一些HTML保留在模板视图之外,例如“主标题或任何外部边框/设置”。
  3. 想要使用URL.Action("action","controller")从控制器呈现具有逻辑(来自控制器)的局部视图。

使用模板的原因:

  1. 希望删除ForEach(Iterator)。模板足够聪明,能够自动识别模型为列表类型。
  2. 模型中心的逻辑。如果在同一个displayfor模板文件夹中找到多个视图,则呈现将取决于传递的模型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接