Search code examples
c#syntaxhtml-tabletablesorterasp.net-3.5

On asp:Table Control how do we create a thead?


From an MSDN article on the subject, we can see that we create a TableHeaderRowthat contains TableHeaderCells.

But they add the table header like this:

myTable.Row.AddAt(0, headerRow);

which outputs the HTML:

<table id="Table1" ... > 
<tr> 
    <th scope="column" abbr="Col 1 Head">Column 1 Header</th>
    <th scope="column" abbr="Col 2 Head">Column 2 Header</th>
    <th scope="column" abbr="Col 3 Head">Column 3 Header</th> 
</tr>
<tr> 
    <td>(0,0)</td>
    <td>(0,1)</td>
    <td>(0,2)</td>
</tr>

...

and it should have <thead> and <tbody> (so it works seamless with tablesorter) :)

<table id="Table1" ... > 
<thead>
<tr> 
    <th scope="column" abbr="Col 1 Head">Column 1 Header</th>
    <th scope="column" abbr="Col 2 Head">Column 2 Header</th>
    <th scope="column" abbr="Col 3 Head">Column 3 Header</th> 
</tr>
</thead>
<tbody>
<tr> 
    <td>(0,0)</td>
    <td>(0,1)</td>
    <td>(0,2)</td>
</tr>
    ...
    </tbody>

the HTML aspx code is

<asp:Table ID="Table1" runat="server" />

How can I output the correct syntax?


Just as information, the GridViewcontrol has this built in as we just need to set the Accesbility and use the HeaderRow

gv.UseAccessibleHeader = true;
gv.HeaderRow.TableSection = TableRowSection.TableHeader;
gv.HeaderRow.CssClass = "myclass";

but the question is for the Table control.


Solution

  • Just found a way to do this, we do need to use our own controls that inherit from the base control, for example a Table

    public class myTable : System.Web.UI.WebControls.Table
    {
        protected override void OnPreRender(EventArgs e)
        {
            Table table = Controls[0] as Table;
    
            if (table != null && table.Rows.Count > 0)
            {
                // first row is the Table Header <thead>
                table.Rows[0].TableSection = TableRowSection.TableHeader;
                // last row is the Footer Header <tfoot> (comment for not using this)
                table.Rows[table.Rows.Count - 1].TableSection = TableRowSection.TableFooter;
    
                FieldInfo field = typeof(WebControl).GetField("tagKey", BindingFlags.Instance | BindingFlags.NonPublic);
                foreach (TableCell cell in table.Rows[0].Cells)
                    field.SetValue(cell, HtmlTextWriterTag.Th);
            }
            base.OnPreRender(e);
        }
    }
    

    works fine with DataGrid as well

    public class myDataGrid : System.Web.UI.WebControls.DataGrid 
    {
        protected override void OnPreRender(EventArgs e)
        {
            Table table = Controls[0] as Table;
    
            if (table != null && table.Rows.Count > 0)
            {
                // first row is the Table Header <thead>
                table.Rows[0].TableSection = TableRowSection.TableHeader;
                // last row is the Footer Header <tfoot> (comment for not using this)
                table.Rows[table.Rows.Count - 1].TableSection = TableRowSection.TableFooter;
    
                FieldInfo field = typeof(WebControl).GetField("tagKey", BindingFlags.Instance | BindingFlags.NonPublic);
                foreach (TableCell cell in table.Rows[0].Cells)
                    field.SetValue(cell, HtmlTextWriterTag.Th);
            }
            base.OnPreRender(e);
        }
    }
    

    then for example you just need to use it instead the base control:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            myGridView dg = new myGridView();
            dg.DataSource = new string[] { "1", "2", "3", "4", "5", "6" };
            dg.DataBind();
    
            ph.Controls.Add(dg);
        }
    }
    

    and in aspx page, just add a place holder like:

    <asp:PlaceHolder ID="ph" runat="server" />
    

    full example in pastebin