2009-10-07 56 views
1

我試圖在數據綁定控件中顯示一組表格數據,但我需要對錶格進行旋轉,以使各個記錄是表格列而不是表格行。最終結果是具有固定列數和可變行數的表格,每個行顯示所有記錄的單個字段like this。由於必須爲每個字段定義< tr/>標籤,而不是每個記錄,因此轉發器不適合用於此目的。我想知道的是,如果有任何內置的ASP.NET控件可以實現我想要的。我正在調用ListView控件,但是我不確定它實際上是否能夠描述我所描述的內容。ASP.NET - 顯示數據透視表的理想控件

實際上,假設像記錄以下內容:

 Number Yardage Par ... 
(Hole) 1  300  4 ... 
(Hole) 2  275  4 ... 
(Hole) 3  390  5 ... 
(Hole) ... ... ... ... 

我需要顯示:

  1 2 3 ... 
Yardage: 300 275 390 ... 
    Par: 4 4 5 ... 
    ...: ... ... ... ... 

一個可行的替代與< TR/>標籤的戰鬥當然會是使用顯示:內嵌<divs>與一些優雅的CSS,但如果我可以保留<表>結構,這將是理想的。

謝謝!

回答

5

我最近遇到了同樣的問題,並且在尋找答案時發現大多數解決方案都圍繞着源數據進行了旋轉。

我想到問題不在於源數據,而在於我們想要呈現它的方式。雖然上面的Chris的回答確實會改變我在我的需求中找到的渲染點的數據,如果我需要模板化的網格視圖,它的靈活性不夠。那麼它發生了,或許更好的解決方案是捕獲一個網格的表格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); 
     } 
    } 
} 

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; 
    } 


} 
2

你最好打賭可能是創建你自己的服務器控件。

我已經通過創建擴展GridView的自定義服務器控件來做類似於此的事情。然後,我旋轉DataSource並在數據綁定上動態添加列到gridview。

我使用了GridView方法來保持外觀和行爲類似於我的網站的其他部分。或者,您可以創建一個更簡單的自定義控件,爲Render方法中的表格創建html。

祝你好運。

編輯:這裏是如何使基於表的服務器控件爲例(這並不難,但是要注意我沒有測試這個...):

public class PivotTable : Control 
{ 
    protected Table pivotTable = new Table(); 
    private DataTable _datasource; 
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
    Category("Data"), Browsable(true), 
    Description("Gets and sets the DataSource for the Control. Needs to be a DataTable")] 
    public DataTable DataSource 
    { 
     get { return _datasource; } 
     set 
     { 
      if (value.GetType() == typeof(DataTable)) 
      { 
       throw new Exception("DataSource must be a DataTable."); 
      } 
      _datasource = value; 
     } 
    } 

    public override ControlCollection Controls 
    { 
     get 
     { 
      EnsureChildControls(); 
      return base.Controls; 
     } 
    } 

    protected override void CreateChildControls() 
    { 
     Table tbl = new Table(); 
     foreach (DataColumn dc in DataSource.Columns) 
     { 
      TableRow tr = new TableRow(); 
      TableHeaderCell header = new TableHeaderCell(); 
      header.Text = dc.ColumnName; 
      tr.Controls.Add(header); 

      foreach (DataRow dr in DataSource.Rows) 
      { 
       TableCell tc = new TableCell(); 
       tc.Text = dr[dc.ColumnName].ToString(); 
       tr.Controls.Add(tc); 
      } 

      tbl.Controls.Add(tr); 
     } 

     Controls.Add(tbl); 
    } 
} 
+0

這不是一個壞建議。我一直想讓自己學習如何在一段時間內構建一個模板控件。 :) – 2009-10-07 18:39:58

0

你可以使用表格組件,但你需要努力工作才能得到你想要的。對我來說最好的解決方案是使用GridView.You可以將pivoted結果集填充到數據表中,並動態地創建數據表列和行。當你獲得所需的格式時,你可以將數據表綁定到GridView。

我以前做過類似的事情,實施起來比較容易,而不是試圖創建自己的控件。

0

第三方交叉表控件可用。首先想到DevXpress ASPxPivotGrid

如果您需要純粹用於獨立非交互式報表的交叉表,那麼您可以考慮使用單獨的報表工具並將報表嵌入到ASP.NET報表查看器控件中。對於表格和矩陣數據,SQL Server Reporting Services 2008有一個很好的tablix regionTelerik Reporting也有交叉表。但是,如果您的需求很簡單且定義明確,按照建議推出HTML表格控件可能是最快的解決方案。