Nested @Html.DisplayFor(model => baseClass, “BaseC

2019-02-13 09:45发布

问题:

Several sub-classes (e.g. Cheese) share common properties derived from a base class (Product) with properties like SKU, Name and Description.

To avoid duplication when rendering display/editor templates, I want each sub-class template (Cheese.cshtml) to render its unique fields below that of its shared common base class template (Product.cshtml).

However, casting from the derived class to the base class (Product)cheese and trying to display its template inside the sub-class template has no effect.

DisplayTemplate File structure:

.\Views\Shared\DisplayTemplates
    .\Product.cshtml -- renders common base class fields
    .\Cheese.cshtml -- renders unique class fields and calls Product.cshtml

Cheese.chtml:

@model Application.Data.Models.Cheese

@{
    var product = (Application.Data.Models.Part)Model;
}

Base Product Fields:
@Html.DisplayFor(x => products, "Product") @* no effect! *@

<div class="field">
    <div class="display-label">@Html.LabelFor(m => Model.UniqueProperty)</div>
    <div class="display-field">@Html.DisplayFor(m => Model.UniqueProperty)</div>
</div>

Casting to the base class and rendering the Product.cshtml template works fine from a View, but not from within the sub-class template.

How can I render a common template for my base class from within my sub-class templates?

回答1:

Solution Found

@Html.DisplayFor(...) cannot be nested, so you have to use @Html.Partial in your derived template like so:

@Html.Partial("~/Views/Shared/DisplayTemplates/Product.cshtml", product) %>

Or, if your file structure allows it, a more terse path:

@Html.Partial("DisplayTemplates/Product", product)


回答2:

It can be debatable if it is a good idea to template complicated objects, or if my approach to nested templates is a hack or not. The advantage of this is having a single template for the parent and child can both have templates rather than having to choose/use partial views.

All that aside, templated views can be nested, if you use a partial view as an go between.

The outside template will have something like below where you want to place the inner template:

Html.RenderPartial("SharedDisplayGoBetweenForFoo", item);  

The shared partial would look like this:

@model Foo

@Html.DisplayFor(a => a);

The inner template would then be called and would look like any other.

So your example would look like

Cheese.cshtml:

@model Application.Data.Models.Cheese

@{
    var product = (Application.Data.Models.Part)Model;
}

Base Product Fields:
@Html.DisplayFor(x => products, "Product") @* no effect! *@

<div class="field">
    <div class="display-label">@Html.LabelFor(m => m.UniqueProperty)</div>
    <div class="display-field">@Html.RenderPartial("SharedPartialProductGobetween", Model.UniqueProperty)</div>
</div>

SharedPartialProductGobetween.cshtml:

@model Product

@Html.DisplayFor(a => a);

Your Product Template wouldn't change.