首页 文章

在TagBuilder中使用显示模板

提问于
浏览
0

我正在尝试构建一个输出表行的HtmlHelper扩展:

public static MvcHtmlString AddRow(this HtmlHelper helper, string label, params object[]  values)
{
    TagBuilder tdBuilder = new TagBuilder("td");
    tdBuilder.MergeAttribute("colspan", "4");
    tdBuilder.AddCssClass("no-bg");
    TagBuilder divBuilder = new TagBuilder("div");
    divBuilder.AddCssClass("column-label");
    divBuilder.AddCssClass("column-align-left");
    divBuilder.InnerHtml = label;
    tdBuilder.InnerHtml = divBuilder.ToString();

    TagBuilder trBuilder = new TagBuilder("tr");
    trBuilder.InnerHtml = tdBuilder.ToString();

    foreach (var value in values)
    {
        TagBuilder tdValueBuilder = new TagBuilder("td");
        tdValueBuilder.InnerHtml = value.ToString(); // I want to have display template here
        trBuilder.InnerHtml += tdValueBuilder.ToString();
    }

    return MvcHtmlString.Create(trBuilder.ToString());
}

虽然这确实正确地呈现了行,但它并没有正确地格式化所有值(例如,DateTime) .

等效的局部视图可以使用DisplayFor方法:

<tr>
<td colspan="4" class="no-bg">
    <div class="column-label column-align-left">
        @Model.Label
    </div>
</td>
@foreach (var value in Model.Values)
{
    <td>
        @Html.DisplayFor(m => value)
    </td>
}

局部视图中的模型是自定义模型,具有Label,List Values等属性 . DisplayFor使用任何存在的显示模板正确呈现值 . 那么如何用TagBuilder实现相同的结果呢?

实际的方法有点复杂(使用可选参数和附加逻辑),所以我更喜欢使用HtmlHelper扩展 .

辅助方法将用于为大型模型的特定属性呈现表行,如下所示:

@Html.AddRow("myLabel1", Model.Foo.Bars.MyValue1)
@Html.AddRow("myLabel2", Model.Foo.MyOtherValue4a, Model.Foo.MyOtherValue4b)
@* etc. *@

1 回答

  • 0

    我找到了一个解决方案,通过仔细观察DisplayFor帮助程序 . 解决方案是将方法更改为使用与DisplayFor帮助程序相同的签名,该帮助程序使用通用的TModel和TValue .

    所以我现在拥有的是:

    public static MvcHtmlString AddRowFor<TModel, TValue>(this HtmlHelper<TModel> helper, string label, params Expression<Func<TModel, TValue>>[] values)
        {
            TagBuilder tdBuilder = new TagBuilder("td");
            tdBuilder.MergeAttribute("colspan", "4");
            tdBuilder.AddCssClass("no-bg");
            TagBuilder divBuilder = new TagBuilder("div");
            divBuilder.AddCssClass("column-label");
            divBuilder.AddCssClass("column-align-left");
            divBuilder.InnerHtml = label;
            tdBuilder.InnerHtml = divBuilder.ToString();
    
            TagBuilder trBuilder = new TagBuilder("tr");
            trBuilder.InnerHtml = tdBuilder.ToString();
    
            foreach (var value in values)
            {
                TagBuilder tdValueBuilder = new TagBuilder("td");
    
                // the magic happens here
                var metadata = ModelMetadata.FromLambdaExpression(value, helper.ViewData);
                tdValueBuilder.InnerHtml = helper.DisplayFor(_ => metadata.Model).ToHtmlString();
    
                trBuilder.InnerHtml += tdValueBuilder.ToString();
            }
    
            return MvcHtmlString.Create(trBuilder.ToString());
        }
    

    用法:

    @Html.AddRowFor("myLabel1", m => Model.Foo.Bars.MyValue1)
    @Html.AddRowFor("myLabel2", m => Model.Foo.MyOtherValue4a, m => Model.Foo.MyOtherValue4b)
    

    唯一让我困扰的是我必须引入模型,即使我实际上并没有在辅助方法中使用它 .

相关问题