EditorTemplates are great as they allow some kind of "polymorphism" in the razor views. But I miss one “brick” to complete polymorphism support:
Can EditorTemplate for a special type inherit from EditorTemplate for a generic type?
Long version:
Considering
class SpecialChild : GeneralChild { } class Parent { GeneralChild AGeneralChild { get; set; } SpecialChild ASpecialChild { get; set; } }
and two editor templates
@* GeneralChild.cshtml *@ @model GeneralChild <span>GeneralChild</span> @* SpecialChild.cshtml *@ @model SpecialChild <span>SpecialChild is a</span> <span>GeneralChild</span>
What I get (that's why I call it "polymorphism"):
@* Index.cshtml *@ @Html.EditorFor(m => m.AGeneralChild) // prints "<span>GeneralChild</span>", however @Html.EditorFor(m => m.ASpecialChild) // prints "<span>SpecialChild is a</span> <span>GeneralChild</span>"
That is, despite the fact that SpecialChild is GeneralChild, and there is a template for GeneralChild, it automatically selects the SpecialChild.cshtml template. In addition, if I delete this template, it returns to the GeneralChild.cshtml template. In other words, you can reuse a common template or, if necessary, override it.
Now for what I would like to:
I would like to reuse the GeneralChild.cshtml template to define the SpecialChild.cshtml template as a call to the "base method" in C #. In pseudo code:
@* SpecialChild.cshtml *@ baseEditorFor() @section SpecificPart { <span>SpecialChild is a </span> } @* GeneralChild.cshtml *@ @Html.RenderSection("SpecificPart") <span>GeneralChild</span>
Is something like this supported?
What I have tried so far:
GeneralChild.cshtml:
@model GeneralChild @{ var extend = ViewData.ContainsKey("Extend") ? (MvcHtmlString)ViewData["Extend"] : null; } @if (extend != null) { @extend } <span>GeneralChild</span>
SpecificChild.cshtml:
@model SpecialChild @Html.EditorFor( m => m, // call editor for my model "GeneralChild", // but call "base" instead of "this" new { // Hand the HTML to insert as ViewData parameter Extend = new MvcHtmlString("<span>SpecialChild is a </span>") })
Unfortunately, @Html.EditorFor(m => m) does nothing. This makes sense because m => m does not match the original m => m.ASpecialChild .
I thought that I could create an expression tree manually, but then I realized that the type arguments in the editor template (of course) are different from those specified in Index.cshtml. @Html in the original call is <Parent> , while in the template it is <SpecialChild> .
Then I tried a different approach, which I got closest so far:
Inside Index.cshtml, I define a razor helper:
@helper SpecialChildEditorFor(Expression<Func<Parent,SpecialChild>> expression) { @Html.EditorFor( expression, "GeneralChild", new { Extend = new MvcHtmlString("<span>SpecialChild is a </span>") }) }
Then I call it instead of EditorFor :
@SpecialChildEditorFor(m => m.ASpecialChild)
But, of course, this is not enough of the completely initially mentioned advantages - I can’t just drop this fragment in the EditorTemplates directory, thereby "overriding" the GeneralChild.cshtml template. In addition, it must be explicitly called (so that we have lost the "polymorphism" too). Moreover, the shaver assistant is attached to the Index.cshtml page: * It must be defined on the page where it is used. * It relies on expression to have the same type arguments as the page the page needs.