Skip to main content
Email Password   helpLost your password?

FreezeGridViewHeader

Introduction

Frozen header for an ASP.NET GridView is a common requirement for web developers nowadays. For usability reasons, frozen or fixed headers are a must for data viewing controls like DataGrid, GridView, or a raw HTML table etc. You must have observed that, in Excel, you can freeze the header cells of your spread sheet. When you scroll down, the headers are always visible, making your sheet more readable. The same effect is often needed in a GridView control, especially if you are displaying many records at a time. In this article, I will explain a technique that will allow you to achieve this with ease.

Conceptual Discussions

We all know that after executing the server-side code, raw HTML is returned to the browser, and the browser just shows the HTML. Obviously, a GridView needs to be converted to an HTML table. So, we need to do some customizations on the returned table to reach our goal. There are some steps to do that customization that are mentioned below:

  1. Take away the table row which usually represents the header and assign it to a newly created “<THEAD>” tag.
  2. Make the rest of table/grid row scrollable by limiting the height of the table and adding the “overflow: auto” attribute inside both “<TBODY>” and “<DIV>”. “<DIV>” is simply a wrapper over the grid which helps to represent the scrollable option.
  3. Now, fix/freeze the “<THEAD>” using a technique applicable to the browser (because different browsers act differently in this case).

Now, whenever you scroll the grid rows, the header always stays on the top row.

Using the Code

The complete sample code is given below. You can also download the sample project from the above link.

<%@ Page Language="C#" AutoEventWireup="true" 
         CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<style type="text/css">
    .WrapperDiv 
    {
        width:560px;height:290px;border: 1px solid black;
    }        
    .WrapperDiv TH 
    {
        /* Needed for IE */
         position: relative;
    }
    .WrapperDiv TR 
    {
        /* Needed for IE */
        height:0px;
    }
    .ScrollContent 
    {
        /* Needed for Opera */
        display: block;
        overflow: auto;
        width: 100%;
        height: 250px;
    }
    .FixedHeader
    {
        /* Needed for opera */
        display: block;
    }
    
</style>

<script runat="server">
  ICollection CreateDataSource( )
  {
    System.Data.DataTable dt = new System.Data.DataTable();
    System.Data.DataRow dr;
    dt.Columns.Add(new System.Data.DataColumn("Product Id", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("Product Name", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("Product Price", typeof(System.Decimal)));
    dt.Columns.Add(new System.Data.DataColumn("Manufacture Time", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("Expired Time", typeof(System.String)));
    
    for (int i = 1; i <= 50; i++)
    {
      System.Random rd = new System.Random(Environment.TickCount * i); ;
      dr = dt.NewRow();
      dr[0] = i.ToString();
      dr[1] = "Sample Product" + i.ToString();
      dr[2] = System.Math.Round(rd.NextDouble() * 100, 2);
      dr[3] = "September/2008";
      dr[4] = "September/2012";
      dt.Rows.Add(dr);
    }
    System.Data.DataView dv = new System.Data.DataView(dt);
    return dv;
  }

  protected void Page_Load( object sender, EventArgs e )
  {
    if (!IsPostBack)
    {
      GridView1.DataSource = CreateDataSource();
      GridView1.DataBind();
    }
  }
  
</script>

<script type="text/ecmascript">

    var headerHeight = 8;

    /// <summary>
    ///  Responsible for call appropriate function according to browser
    ///  for Browser Compatibility
    /// </summary>
    function onLoad()
    {
        if(navigator.appName == "Opera")
        {
            freezeGridViewHeaderForOpera('GridView1');
        }
        else
        {
            freezeGridViewHeaderForIEAndFF('GridView1','WrapperDiv');
        }
    }
    
    /// <summary>
    ///  Used to create a fixed GridView header and allow scrolling
    ///  for IE and FF (Tested in IE-7 and FF-3.0.3)
    /// </summary>
    /// <param name="gridViewId" type="String">
    ///   Client-side ID of the GridView control
    /// </param>
    /// <param name="wrapperDivCssClass" type="String">
    ///   CSS class to be applied to the GridView's wrapper div element.
    /// </param>
    function freezeGridViewHeaderForIEAndFF(gridViewId,wrapperDivCssClass) 
    {
        var grid = document.getElementById(gridViewId);
        if (grid != 'undefined')
        {
            grid.style.visibility = 'hidden';
            
            var div = null;
            if (grid.parentNode != 'undefined') 
            {
                //Find wrapper div output by GridView
                div = grid.parentNode;
                if (div.tagName == "DIV")
                {
                    div.className = wrapperDivCssClass;  
                    div.style.overflow = "auto";             
                }
            }  
                       
            var grid = prepareFixedHeader(grid);
            var tbody = grid.getElementsByTagName('TBODY')[0];
            
            //Needed for Firefox
            tbody.style.height = (div.offsetHeight -  headerHeight) + 'px';

            tbody.style.overflowX = "hidden";
            tbody.overflow = 'auto';
            tbody.overflowX = 'hidden';
             
            grid.style.visibility = 'visible';
        }
    }
    
    /// <summary>
    ///  Used to create a fixed GridView header and allow scrolling
    ///  for Opera (Tested in Opera-9.2)
    /// </summary>
    /// <param name="gridViewId" type="String">
    ///   Client-side ID of the GridView control
    /// </param>
    function freezeGridViewHeaderForOpera(gridViewId)
    {
        var grid = document.getElementById(gridViewId);
        if (grid != 'undefined')
        {
            grid = prepareFixedHeader(grid);

            var headers = grid.getElementsByTagName('THEAD')[0];
            headers.className = "FixedHeader";
            
            var tbody = grid.getElementsByTagName('TBODY')[0];
            tbody.className = "ScrollContent";
            var cells = tbody.childNodes[0];

            for(var i = 0; i < cells.childNodes.length;i++)
            {
                var tableCell = cells.childNodes[i];
                var tableCellWidth = getStyle(tableCell,'width')
                var headerCell = headers.childNodes[0].childNodes[i];

                var headerCellWidth = getStyle(headerCell,'width');

                if(widthPxToInt(tableCellWidth) > widthPxToInt(headerCellWidth))
                {
                    headerCell.style.width=(widthPxToInt(tableCellWidth) - 10) + "px";
                }
                else
                {
                    tableCell.style.width=(widthPxToInt(headerCellWidth) - 10) + "px";
                }
            }
        }
    }
    
    /// <summary>
    ///  Used to prepare a fixed GridView header
    /// </summary>
    /// <param name="grid" type="GridView">
    ///   The Reference Of GridView control
    /// </param>
    function prepareFixedHeader(grid)
    {
        //Find DOM TBODY element and  and 
        var tags = grid.getElementsByTagName('TBODY');
        if (tags != 'undefined')
        {
            var tbody = tags[0];
            
            var trs = tbody.getElementsByTagName('TR');

            if (trs != 'undefined') 
            {
                headerHeight += trs[0].offsetHeight;
                
                //Remove first TR tag from it        
                var headTR = tbody.removeChild(trs[0]);
                
                //create a new element called THEAD
                var head = document.createElement('THEAD');
                head.appendChild(headTR);
                
                //add to a THEAD element instead of TR so CSS styles
                //can be applied properly in both IE and FireFox
                grid.insertBefore(head, grid.firstChild);
            }
       }
       
       return grid;
    }
    
    function getStyle(oElm, strCssRule)
    {
        var strValue = "";
        if(document.defaultView && document.defaultView.getComputedStyle){
           strValue = document.defaultView.getComputedStyle(oElm, 
                               "").getPropertyValue(strCssRule);
        }
        else if(oElm.currentStyle){
            strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
                return p1.toUpperCase();
            });
            strValue = oElm.currentStyle[strCssRule];
        }
        return strValue;
    }
    
    /// <summary>
    ///  Used to convert from Pxel to Integer
    /// </summary>
    /// <param name="width" type="String">
    ///  Width of any thing like GridHeader,GridCell
    /// </param>    
    function widthPxToInt(width)
    {
        width = width.substr(0,width.length-2);
        return new Number(width);
    }
    
    
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:GridView ID="GridView1" runat="server" 
              Font-Size="12px" BackColor="#FFFFFF"
              GridLines="Both" CellPadding="4" Width="560px">
          <HeaderStyle BackColor="#EDEDED" Height="26px" />
        </asp:GridView>
    </div>
    </form>
</body>
</html>

<script type="text/ecmascript">   
    window.onload = onLoad();
</script>

Browser Compatibility

Since I have used JavaScript and CSS to solve this problem, there is no doubt that it will raise the question, “Is the solution compatible for all browsers?”. If you Google, you will find lots of solutions for this problem. But, I have not yet found any client-side solution that supports all the browsers. Most of the solutions support Firefox and IE. But, very few support Opera.

I did test my provided solution in FireFox-3.0.3 , IE-7, and Opera-9.2 and got successful results.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
Generalusing this code in vb Pin
loxzide
18:04 30 Sep '09  
GeneralFreeze header. freeze footer and freeze left column Pin
sandeepkumars
2:07 10 Aug '09  
Generalworks in ie 6,7 but not 8 Pin
walshy007
4:52 20 Jul '09  
GeneralRe: works in ie 6,7 but not 8 Pin
Member 3918870
10:32 21 Jul '09  
GeneralExample in Visual Basic Pin
Revalk
10:45 1 Jul '09  
General**Horizontal scroll bar** Pin
scorpioyas
1:32 1 Jul '09  
Generaltable header in IE overlap the scroll bar Pin
MB_1981
21:33 18 Jun '09  
Generalin IE on scroll it show the text behind the header [modified] Pin
MB_1981
22:18 16 Jun '09  
Generalhow to remove the horizontal bar Pin
MB_1981
20:47 15 Jun '09  
GeneralVery Good - Just need some tweaks for Chrome/Safari Pin
andrew6ger
4:52 19 May '09  
Generalfreeze the header & Column of gridview Pin
nadeem2003
20:43 1 Feb '09  
GeneralProblem when executing with grid view in content pages Pin
Qot
21:03 15 Jan '09  
GeneralRe: Problem when executing with grid view in content pages Pin
DrShrinker
9:27 22 Apr '09  
GeneralWhat about sorting? Pin
eashwar v
19:44 19 Dec '08  
GeneralCouple of problems I noticed after building the sample... Pin
Justin Freitas
4:32 1 Nov '08  
GeneralRe: Couple of problems I noticed after building the sample... [modified] Pin
Razwan Kader
19:51 1 Nov '08  
GeneralRe: Couple of problems I noticed after building the sample... Pin
Greg Hazzard
2:50 14 Dec '08  
GeneralWell done Pin
BigJim61
14:05 31 Oct '08  
GeneralRe: Well done Pin
Razwan Kader
20:07 1 Nov '08  
Generalnice article Pin
nhm tanveer hossain khan (hasan)
13:35 31 Oct '08  
GeneralRe: nice article Pin
Razwan Kader
20:08 1 Nov '08  


Last Updated 31 Oct 2008 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2009