12

Setting TableSection = TableRowSection.TableHeader after the grid is bound works initially, putting the header row in thead. After a postback (where the grid is not re-bound) the header row reverts to the table body. I expect the header row to stay in thead; can someone explain why this is not the case or what I am doing wrong?

Sample:

Click the button to cause a postback. The header is not orange after the postback since it's not in thead anymore.

aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="gridtest.aspx.cs" Inherits="ffff.gridtest" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <style type="text/css">
    thead th { background-color:Orange;}
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <div><asp:Button ID="Button1" runat="server" Text="Button" />
    &nbsp;this button is here just to trigger a postback</div>
    <asp:GridView ID="gv1" runat="server"></asp:GridView>
    </form>
</body>
</html>

code

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace ffff
{
    public partial class gridtest : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            gv1.DataBound += new EventHandler(gv1_DataBound);
            if (!IsPostBack) { BindGrid(); }
        }
        void Page_PreRender(object sender, EventArgs e)
        {
            if (gv1.HeaderRow != null)
                System.Diagnostics.Debug.WriteLine(gv1.HeaderRow.TableSection); // still TableHeader after postback
        }
        void gv1_DataBound(object sender, EventArgs e)
        {
            if (gv1.HeaderRow != null)
            {
                gv1.HeaderRow.TableSection = TableRowSection.TableHeader;
            }
        }
        private void BindGrid()
        {
            gv1.DataSource = this.Page.Controls;
            gv1.DataBind();
        }
    }
}
lincolnk
  • 11,218
  • 4
  • 40
  • 61
  • possible duplicate of [How do I get Gridview to render THEAD?](http://stackoverflow.com/questions/309101/how-do-i-get-gridview-to-render-thead) – Alex Angas Jan 18 '15 at 23:49

3 Answers3

19

Use the Pre_Render_Complete event instead to add the table section. This will ensure the thead section is always added. As you are currently doing it on DataBound the section will only be added when the data is bound.

protected override void OnPreRenderComplete(EventArgs e)
    {
        if (gv1.Rows.Count > 0)
        {
            gv1.HeaderRow.TableSection = TableRowSection.TableHeader;                
        }
    }

Feel free to change the row check I use to checking the Header Row exists as you currently do.

Jon P
  • 19,442
  • 8
  • 49
  • 72
  • I'm using a standard `GridView` rather than inheriting from it so I attached an event handler to `PreRender` and this works. I don't understand why though- `gv1.HeaderRow.TableSection` has a value of `TableHeader` before and after this assignment. Is there something going on within the setter that's responsible for making this render correctly? – lincolnk Jul 08 '11 at 14:24
  • Unfortunately I cant give you an answer to why this is the case, only that it works. My OnPrerenderComplete overide is actually at a page level. Often if I have several grids on a page I will load up the all table head sections in one spot. I might have a little investigation/experiment into the mechanics of this in light of your follow up question – Jon P Jul 10 '11 at 23:44
  • Interesting. When Stepping through my page OnPreRenderComplete shows HeaderRow.TableSection as TableBody before the assignment, ensuring ViewState was enabled. ViewState is saved after the PreRenderComplete event (http://msdn.microsoft.com/en-us/library/ms178472.aspx) so that isn't the issue. – Jon P Jul 11 '11 at 00:48
  • 2
    I needed to use this in a Usercontrol, so I used the OnPreRender event and it worked fine. – Nathan Koop Feb 22 '12 at 18:57
  • Thank you. It still threw exceptions for me, so I expanded your approach to fit my needs. See my answer here: http://stackoverflow.com/a/19846059/555798 – MikeTeeVee Nov 07 '13 at 20:35
5

You must set TableSection after DataBind method.

 gv1.DataSource = this.Page.Controls;
 gv1.DataBind();
 gv1.HeaderRow.TableSection = TableRowSection.TableHeader; 
  • 1
    Yes, I'm doing that. The question is why does the grid render the default way after a postback, even when `TableSection` is still set as `TableHeader`. – lincolnk Sep 21 '13 at 00:07
  • From http://forums.asp.net/t/1004097.aspx?GridView+HeaderRow+null+ - HeaderRow is null when your datatable is empty (or, in this case, this.Page.Controls is empty) – jflaga Jan 27 '15 at 13:03
3

Just put the below code in prerender event of gridview

protected void gv_PreRender(object sender, EventArgs e)
{
    if (gv.Rows.Count > 0)
    {
        gv.UseAccessibleHeader = true;
        gv.HeaderRow.TableSection = TableRowSection.TableHeader;
    }
}
Mark Bell
  • 28,985
  • 26
  • 118
  • 145
Vinay
  • 31
  • 1