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?
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)
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.