Click here to Skip to main content
15,563,124 members
Articles / Web Development / CSS
Article
Posted 31 Oct 2008

Stats

187.7K views
4.3K downloads
69 bookmarked

Freezing ASP.NET GridView Header With JavaScript and CSS

Rate me:
Please Sign up or sign in to vote.
4.55/5 (14 votes)
31 Oct 2008CPOL2 min read
Freeze an ASP.NET GridView header using JavaScript and CSS.

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.

ASP.NET
<%@ 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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) somewhere in...
Bangladesh Bangladesh
Working in a Nordic company, developing some really interesting solutions for GSM Mobile Service Providers in Bangladesh. I work as a senior software developer there. Developed framework of challenging web based application. Build and manage a complete dynamic accounting and inventory management system which is tag based software. Enjoy learning about latest technology. Main working arenas are asp.net 2.0/3.5.

Comments and Discussions

 
Generalfreeze the header & Column of gridview Pin
nadeem20031-Feb-09 20:43
nadeem20031-Feb-09 20:43 
GeneralProblem when executing with grid view in content pages Pin
Qot15-Jan-09 21:03
Qot15-Jan-09 21:03 
GeneralRe: Problem when executing with grid view in content pages Pin
DrShrinker22-Apr-09 9:27
DrShrinker22-Apr-09 9:27 
QuestionWhat about sorting? Pin
eashwar v19-Dec-08 19:44
eashwar v19-Dec-08 19:44 
GeneralCouple of problems I noticed after building the sample... Pin
Justin Freitas1-Nov-08 4:32
Justin Freitas1-Nov-08 4:32 
GeneralRe: Couple of problems I noticed after building the sample... [modified] Pin
Razwan Kader1-Nov-08 19:51
Razwan Kader1-Nov-08 19:51 
GeneralRe: Couple of problems I noticed after building the sample... Pin
Greg Hazz14-Dec-08 2:50
Greg Hazz14-Dec-08 2:50 
GeneralWell done Pin
BigJim6131-Oct-08 14:05
BigJim6131-Oct-08 14:05 
This has to be the easiest way I've ever seen to handle this all-too-common problem. Nicely explained, good article!
GeneralRe: Well done Pin
Razwan Kader1-Nov-08 20:07
Razwan Kader1-Nov-08 20:07 
Generalnice article Pin
nhm tanveer hossain khan (hasan)31-Oct-08 13:35
nhm tanveer hossain khan (hasan)31-Oct-08 13:35 
GeneralRe: nice article Pin
Razwan Kader1-Nov-08 20:08
Razwan Kader1-Nov-08 20:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.