EditorTemplates很棒,因为它们在剃刀视图中允许某种“多态”。但我缺少一个“砖”来完成多态支持:
特殊类型的EditorTemplate可以从EditorTemplate继承一般类型吗?
长版:
鉴于
class SpecialChild : GeneralChild { }
class Parent
{
GeneralChild AGeneralChild { get; set; }
SpecialChild ASpecialChild { get; set; }
}
和两个编辑模板
@* GeneralChild.cshtml *@
@model GeneralChild
<span>GeneralChild</span>
@* SpecialChild.cshtml *@
@model SpecialChild
<span>SpecialChild is a</span> <span>GeneralChild</span>
我得到的(这就是我称之为“多态性”的原因)是:
@* 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>"
也就是说,即使SpecialChild是GeneralChild并且有一个GeneralChild模板,它也会自动选择SpecialChild.cshtml模板。此外,如果我删除该模板,它将回退到GeneralChild.cshtml模板。换句话说,可以重用一般模板或在必要时覆盖它。
现在我真的喜欢:
我想重用GeneralChild.cshtml模板来定义SpecialChild.cshtml模板,就像在C#中调用“基本方法”一样。在伪代码中:
@* SpecialChild.cshtml *@
baseEditorFor()
@section SpecificPart
{
<span>SpecialChild is a </span>
}
@* GeneralChild.cshtml *@
@Html.RenderSection("SpecificPart") <span>GeneralChild</span>
是否支持此类内容?
到目前为止我尝试过:
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>")
})
不幸的是,@Html.EditorFor(m => m)
没有做任何事情。这是有道理的,因为m => m
与原始m => m.ASpecialChild
的表达式不同。
我以为我可以手工构建表达式树,但后来我意识到编辑器模板中的类型参数(当然)与Index.cshtml中的类型参数不同。原始调用中的@Html
已键入<Parent>
,而在模板中则为<SpecialChild>
。
然后我尝试了另一种方法,这是我到目前为止最接近的方法:
在Index.cshtml中我定义了一个剃刀助手:
@helper SpecialChildEditorFor(Expression<Func<Parent,SpecialChild>> expression)
{
@Html.EditorFor(
expression,
"GeneralChild",
new { Extend = new MvcHtmlString("<span>SpecialChild is a </span>") })
}
然后我称之为EditorFor
:
@SpecialChildEditorFor(m => m.ASpecialChild)
但是当然这缺乏最初提到的优点 - 我不能简单地将这个片段放在EditorTemplates目录中,从而“覆盖”GeneralChild.cshtml模板。此外,它需要被明确调用(所以我们也失去了“多态性”)。更重要的是,剃刀助手绑定到Index.cshtml页面:
*必须在使用它的页面中定义。
*它依赖于expression
具有与页面所需类型相同的类型参数。
答案 0 :(得分:3)
在编辑器模板中使用Partial而不是@Html.EditorFor(m => m, ...)
:
@model SpecialChild
@{
ViewData["Extend"] = new MvcHtmlString("<span>SpecialChild is a </span>");
}
@Html.Partial("~/Views/Shared/EditorTemplates/GeneralChild.cshtml", Model)