ASP.NET - 显示数据透视表的理想控件

Nat*_*lor 1 asp.net listview pivot-table databound-controls

我试图在数据绑定控件中显示一组表格数据,但我需要转动表格,使单个记录是表格列而不是表格行.最终结果是一个具有固定列数和可变行数的表,每个行显示所有记录的单个字段,如下所示.由于必须为每个字段而不是每个记录定义<tr />标签,因此转发器不适合这样做.我想知道的是,是否有任何内置的ASP.NET控件可以实现我想要的.我正在盯着ListView控件,但我不确定它是否实际上能够解释我所描述的内容.

实际上,假设记录如下:

       Number Yardage Par  ...
(Hole)   1     300     4   ...
(Hole)   2     275     4   ...
(Hole)   3     390     5   ...
(Hole)  ...    ...    ...  ...
Run Code Online (Sandbox Code Playgroud)

我需要显示:

           1   2   3   ...
Yardage:  300 275 390  ...
    Par:   4   4   5   ...
    ...:  ... ... ...  ...
Run Code Online (Sandbox Code Playgroud)

与<tr />标签作斗争的可行替代方案当然是使用display:inline <divs>和一些优雅的CSS,但是如果我可以保留理想的<table>结构.

谢谢!

小智 5

我最近遇到了同样的问题,在寻找答案时发现大多数解决方案都围绕着转移源数据.

在我看来,问题不在于源数据,而在于我们希望如何呈现它.尽管克里斯上面的回答看起来确实在渲染点改变数据,但我发现我的需求如果我需要一个模板化的网格视图就不够灵活.就在那时,可能更好的解决问题的方法是捕获网格表的HTML标记并改变它 - 这实际上意味着该解决方案可以绝对应用于任何呈现表标记的控件,并且包含任何模板控件在其中将继续工作.

由于时间压力,我只用网格视图实现了解决方案; 我原本想制作一个模板服务器控件,如果放入任何控件,它会检查它的标记输出并转动其中包含的任何表)

无论如何,这是为网格视图实现此解决方案所需的代码.

自定义服务器控制代码

[ToolboxData("<{0}:PivotGridView runat=server></{0}:PivotGridView>")]
public class PivotGridView : GridView
{
    bool _pivotGrid = true;

    [Browsable(true)]
    public bool PivotGrid
    {
        get 
        { 
            return _pivotGrid; 
        }
        set 
        { 
            _pivotGrid = value; 
            EnsureChildControls(); 
        }
    }

    protected override void RenderContents(HtmlTextWriter output)
    {
        if (_pivotGrid)
        {
            System.IO.TextWriter baseOutputTextWriter = new System.IO.StringWriter();
            HtmlTextWriter baseOutputHtmlWriter = new HtmlTextWriter(baseOutputTextWriter);

            base.RenderContents(baseOutputHtmlWriter);

            output.Write(HtmlParserService.PivotHtmlTableMarkup(baseOutputTextWriter.ToString()));
        }
        else
        {
            base.RenderContents(output);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

HTML解析器服务代码,分离出来以便在其他地方轻松实现.

//... using System.Text.RegularExpressions;

public static class HtmlParserService
{        
    /// <summary>
    /// Takes HTML markup locates any table definition held within it and returns that
    /// markup with the table HTML pivotted
    /// </summary>
    /// <param name="html"></param>
    /// <returns></returns>
    public static string PivotHtmlTableMarkup(string html)
    {
        html = ReplaceShorthandTableTags(html);

        int openingTableTagIndex;
        string openingTableTagText;
        int closingTableTagIndex;
        string tableContentText;

        tableContentText = GetTagContentText("table", html, out openingTableTagIndex, out openingTableTagText, out closingTableTagIndex);

        MatchCollection rows = GetTagMatches("tr", tableContentText);
        if (rows.Count > 0)
        {
            MatchCollection columns = GetTagMatches("(td|th)", rows[0].Value);

            StringBuilder pivottedTableMarkup = new StringBuilder();

            for (int i = 0; i < columns.Count; i++)
            {
                pivottedTableMarkup.Append("<tr>");
                foreach (Match row in rows)
                {
                    if (row.Value.Length > 0)
                    {
                        columns = GetTagMatches("(td|th)", row.Value);

                        if (columns.Count>i)
                        {
                            pivottedTableMarkup.Append(columns[i].Value);
                        }
                    }
                }
                pivottedTableMarkup.Append("</tr>");
            }

            string preTableText = "";
            if (openingTableTagIndex > 1)
            {
                preTableText = html.Substring(1, openingTableTagIndex);
            }

            string postTableText;
            postTableText = html.Substring(closingTableTagIndex, html.Length - closingTableTagIndex);

            string newHtmlWithPivottedTable;
            newHtmlWithPivottedTable = preTableText + openingTableTagText + pivottedTableMarkup.ToString() + postTableText;

            return newHtmlWithPivottedTable;
        }
        else
        {
            return html;
        }

    }

    /// <summary>
    /// Gets the content between the specified tag.
    /// </summary>
    /// <param name="tag">The tag excluding any markup (e.g. "table" not "<table>"</param>
    /// <param name="text">The xml text string to extract content from</param>
    /// <param name="openingTagIndex">Outputs the indexed position of the opening tag</param>
    /// <param name="openingTagText">Outputs the definition of the tag, e.g. it's attributes etc</param>
    /// <param name="closingTagIndex">Outputs the indexed position of the closing tag</param>
    /// <returns></returns>
    public static string GetTagContentText(string tag, string text, out int openingTagIndex, out string openingTagText, out int closingTagIndex)
    {
        string contentText;

        openingTagIndex = text.ToLower().IndexOf("<" + tag);
        openingTagText = text.Substring(openingTagIndex, text.IndexOf(">", openingTagIndex) - openingTagIndex+1);
        closingTagIndex = text.ToLower().LastIndexOf("</" + tag + ">");

        contentText = text.Substring(
            openingTagIndex + openingTagText.Length,
            closingTagIndex - (openingTagIndex + openingTagText.Length) );

        return contentText;
    }

    /// <summary>
    /// Returns a collection of matches containing the content of each matched tag
    /// </summary>
    /// <param name="tag">HTML tag to match.  Exclude opening and close angled braces.
    /// Multiple tags can be matched by specifying them in the following format (tag1|tag2),
    /// e.g. (td|th)</param>
    /// <param name="html"></param>
    /// <returns></returns>
    public static MatchCollection GetTagMatches(string tag, string html)
    {
        Regex regexp = new Regex(@"<" + tag + @"\b[^>]*>(.*?)</" + tag + @">", RegexOptions.IgnoreCase | RegexOptions.Singleline);
        return regexp.Matches(html);
    }

    /// <summary>
    /// Ensures any shorthand XML tags are full expressed, e.g.
    /// <td/> is converted to <td></td>
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    private static string ReplaceShorthandTableTags(string value)
    {
        value=value.Replace("<tr/>", "<tr></tr>");
        value=value.Replace("<td/>", "<td></td>");
        value=value.Replace("<th/>", "<th></th>");

        return value;
    }


}
Run Code Online (Sandbox Code Playgroud)