EditorTemplate继承 - 有没有办法

时间:2014-10-31 10:38:38

标签: c# asp.net-mvc razor mvc-editor-templates

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具有与页面所需类型相同的类型参数。

1 个答案:

答案 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)