微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 为IEnumerable编写MVC HtmlHelper以显示HTML表

我正在尝试编写一个客户 HtmlHelper,它允许从传递IEnumerable< TModel>的视图中轻松创建Html表.其中TModel是模型对象类型.我希望视图中的调用语法是样式的:

@Html.TableFor(model => model.AddedUserID,model => model.ClientID.......,model model => AnothreFildIWantdisplayed));

我首先尝试使用一个表达式首先传递,例如,

@Html.TableFor(model => model.AddedUserID)

一旦有效,我将使用params并使用多个表达式来获得逗号分隔列表.

我的View代码如下所示

@using MyNameSpacetoMyHelper
@model IEnumerable<User>

@{
    ViewBag.Title = "Index";
}
<p>

</p>

@Html.TableFor(model => model.AddedUserID));

我编写HtmlHelper的尝试是:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.UI;

namespace MyNameSpacetoMyHelper
{
    public static class GridExtensions
    {
        public static MvcHtmlString TableFor<TModel,TValue>(this HtmlHelper<IEnumerable<TModel>> html,Expression<Func<TModel,TValue>> expression)
        {
            var writer = new HtmlTextWriter(new StringWriter());

            writer.RenderBeginTag(HtmlTextWriterTag.Table);

            writer.RenderBeginTag(HtmlTextWriterTag.Thead);

            writer.RenderBeginTag(HtmlTextWriterTag.Th);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);

            //Colum Headers
            writer.Write(html.displayNameFor(expression));

            writer.RenderEndTag();
            writer.RenderEndTag();

            writer.RenderEndTag();//Close THead

            //Column Data
            //html.displayFor((Expression<Func<TModel,TValue>>)expression);
            foreach (ViewDataDictionary<TModel> vdm in html.ViewData.Values)
            {
                writer.RenderBeginTag(HtmlTextWriterTag.Tr);
                writer.RenderBeginTag(HtmlTextWriterTag.Td);

                //DOESN'T COMPILE
                html.displayFor(expression);
                writer.RenderEndTag();
                writer.RenderEndTag();
            }


            writer.RenderEndTag(); //Close Header


            return new MvcHtmlString(writer.InnerWriter.ToString());
        }

   }

}

由于以下原因,这不能编译:

html.displayFor(表达);

据我所知,这是因为传递给我的方法的HtmlHelper是针对HtmlHelper< IEnumerable< TModel>>而当使用displayFor时,它需要是HtmlHelper< TModel>.

由于这个错误,似乎可以通过将表头和数据拆分为两个单独的方法调用来实现这一点.从我的视图中我可以调用header方法然后在实际视图中有一个for循环,它为每个调用一个方法一排什么的.像这样的东西

@using MyNameSpacetoMyHelper
@model IEnumerable<User>

@{
    ViewBag.Title = "Index";
}
<p>

</p>

@Html.TableHeadersFor(model => model.AddedUserID));
@foreach (var item in Model) {
       @Html.TableRowsFor(model => model.AddedUserID));
}

这应该有效,因为TableHeadersFor可以调用displayNameExtensions.displayNameFor,它接受HtmlHelper< IEnumerable< TModel>>和TableRowsFor可以采用HtmlHelper< TModel>并使用HtmlHelper< TModel>调用displayExtensions.displayFor.所以不兼容的HtmlHelper类型问题就会消失.

但是,如果可能的话,我不希望这样做,因为我希望调用语法尽可能简单.我的问题的一个基本前提是尝试维护一个简单的调用语法,而无需在视图中编写for循环并复制用于选择列的表达式.这里的全部目的是设计一些可重复使用且易于使用的东西

我在ILSpy中看了一下displayNameExtensions.displayNameFor是如何工作的,因为它处理HtmlHelper< IEnumerable< TModel>>因为它看起来像是一种采用HtmlHelper< IEnuermable< TModel>>的exstension方法.在内部调用HtmlHelper上的扩展方法< TModel>但是ILSpy正在生成代码甚至没有重新编译,因此我无法理解.Net是如何做到这一点的.

这在一种扩展方法中是可能的还是我会被迫拆分它以破坏调用语法?

更新1
我已经成功完成了以下工作:

@Html.BeginTableFor(model => model.AddedUserID,model => model.Active,new { @class = "grid" })


@foreach (var item in Model) {

    @Html.displayRowFor(model => item.AddedUserID,model => item.Active)
}

@Html.EndTableFor()

它并不像我想的那样简洁并涉及一堆工作,特别是因为BeginTableFor和displayRowFor的每个表达式都可以返回不同的类型,这意味着我基本上必须为任意数量的表达式实现一个方法重载(我已经完成了100个所以最多可以工作100列!).这基本上是他们在.Net中使用Action和Func委托的问题,他们必须为不同数量的参数编写不同的版本,例如动作T1,T2,..,T16.它显然非常混乱,但我宁愿有很好的调用语法,而不是避免许多方法重载.

解决方法

看看 this article的某个方向,并根据您的需要进行修改.

首先,您需要这样的HTML扩展:

public static class RazorExtensions {
    public static HelperResult List<T>(this IEnumerable<T> items,Func<T,HelperResult> template) {
        return new HelperResult(writer => {
            foreach (var item in items) {
                template(item).Writeto(writer);
            }
        });
    }
}

然后在HTML中,您可以执行以下操作:

{
    var comics = new[] { 
        new ComicBook {Title = "Groo",Publisher = "Dark Horse Comics"},new ComicBook {Title = "Spiderman",Publisher = "Marvel"}
    };
}

<table>
@comics.List(
  @<tr>
    <td>@item.Title</td>
    <td>@item.Publisher</td>
  </tr>)
</table>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐