所以,标题应该不言自明。

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

They respect model hierarchies when rendering HTML helpers (e.g if you have a "Bar" object on your "Foo" model, the HTML elements for "Bar" will be rendered with "Foo.Bar.ElementName", whilst a partial will have "ElementName"). More robust, e.g if you had a List<T> of something in your ViewModel, you could use @Html.DisplayFor(model => model.CollectionOfFoo), and MVC is smart enough to see it's a collection and render out the single display for each item (as opposed to a Partial, which would require an explicit for loop).

我也听说过DisplayFor呈现一个“只读”模板,但我不明白-我不能扔一个表单在那里吗?

有人能告诉我其他原因吗?有没有比较这三个的列表/文章?


当前回答

Just to give my 2c worth, our project is using a partial view with several jQuery tabs, and each tab rendering its fields with its own partial view. This worked fine until we added a feature whereby some of the tabs shared some common fields. Our first approach to this was to create another partial view with these common fields, but this got very clunky when using EditorFor and DropDownListFor to render fields and drop downs. In order to get the ids and names unique we had to render the fields with a prefix depending on the parent partial view that was rendering it:

    <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和名称。

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

其他回答

使用_partial视图方法,如果:

视图中心逻辑 在这个视图中只保留所有_partial视图相关的HTML。在模板方法中,你必须在模板视图之外保留一些HTML,如“Main Header或任何外部边框/设置”。 想要使用URL.Action("action","controller")渲染逻辑(From controller)的部分视图。

使用Template的原因:

要删除ForEach(迭代器)。Template可以很好地将Model标识为列表类型。它会自动完成的。 模型中心逻辑。如果在同一个displayfortemplate文件夹中发现了多个视图,那么渲染将依赖于传递的模型。

你当然可以自定义DisplayFor来显示一个可编辑的表单。但是约定是DisplayFor为只读而EditorFor为编辑。坚持约定将确保无论您传递给DisplayFor什么,它都将做相同类型的事情。

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

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

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

You did not ask about @Html.Action which also deserves a mention here. You could think of it as a more powerful version of Partial in that it executes a controller child action and then renders a view (which is usually a partial view). This is important because the child action can execute additional business logic that does not belong in a partial view. For example it could represent a shopping cart component. The reason to use it is to avoid performing the shopping cart-related work in every controller in your application.

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

到目前为止还没有提到的另一个区别是,partialview不添加模型前缀,而模板可以 这就是问题所在

Just to give my 2c worth, our project is using a partial view with several jQuery tabs, and each tab rendering its fields with its own partial view. This worked fine until we added a feature whereby some of the tabs shared some common fields. Our first approach to this was to create another partial view with these common fields, but this got very clunky when using EditorFor and DropDownListFor to render fields and drop downs. In order to get the ids and names unique we had to render the fields with a prefix depending on the parent partial view that was rendering it:

    <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和名称。

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