There are several articles on fixed headers. I even wrote one called "Implementing a Fixed GridView Header in ASP.NET." What I discovered was that the technique described in that article and some others doesn't work very well when controls are nested or pages become complex. What I was looking for was a more durable solution.
An Overview of the Solution
Have you ever sat in a presentation listening to a lot of technical details without an idea of where you are going? I have. Many times it would have helped to have a thesis statement, a sort of, overview of what will be learned, why, and how we might get there. Hence this section.
Making a Page with a Scrollable Div and GridView
There are a couple of well-used ways to manage the location of controls. Two popular ways are the HTML Table and HTML Div. In this section, you will use a Div to house the GridView. You could make the Div scrollable or just add enough data to the GridView to make the page scroll. With the totality of the code in this article, either approach will permit the header to scroll correctly. To simplify the creation of the presentation layer, you'll use a scrolling page and a lot of data in a GridView.
To implement a test presentation—web page—you can create a dummy class, use a generic List, and bind that list to a GridView. Before you write the code in Listing 1, drop a GridView on a web page.
Listing 1: A sample class and code that populates a GridView.
Imports System.Collections.Generic Partial Class _Default Inherits System.Web.UI.Page Protected Sub Page_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load If (IsPostBack) Then Return Dim list As List(Of Sample) = New List(Of Sample) Dim I As Integer For I = 1 To 100 list.Add(New Sample(I, "Name" + I.ToString(), I.ToString())) Next GridView1.DataSource = list GridView1.DataBind() End Sub End Class Public Class Sample Private _iD As Integer Public Property ID() As Integer Get Return _iD End Get Set(ByVal Value As Integer) _iD = Value End Set End Property Private _name As String Public Property Name() As String Get Return _name End Get Set(ByVal Value As String) _name = Value End Set End Property Private _filler As String Public Property Filler() As String Get Return _filler End Get Set(ByVal Value As String) _filler = Value End Set End Property ''' <summary> ''' Initializes a new instance of the Sample class. ''' </summary> ''' <param name="iD"></param> ''' <param name="name"></param> ''' <param name="filler"></param> Public Sub New(ByVal iD As Integer, _ ByVal name As String, ByVal filler As String) _iD = iD _name = name _filler = filler End Sub End Class
You can use anything to populate the GridView; it really isn't relevant to the discussion. All you should care about is that you have something that generates an HTML table and enough data to make that table need to scroll.
It is worth noting that ASP.NET web controls are HTML generators that spit out HTML on the server. Basically, if it looks like a duck, it is a duck. That is, a GridView is actually rendered as an HTML table, so this technique will work on anything that is ultimately an HTML table.
Adding the HTML Div and Table Stubs
The GridView will have a header. For the technique for pinning it, you could use the GridView's actual header, but is actually a little easier to use a clone. The reason is that if you pin the GridView's actual header, you have to adjust its position differently when you have scrolled to the top (or you hide row 1), and you might have to account for a positioned header's index when manipulating the data. For these reasons, I elected to use a stub div and table to mimic the fixed header.
Tip: Did you know that a table header is rendered as a <TR> with <TH> children instead of <TD> (cells) children? Did you also know that you can place the row containing the header (or <TH> cells) anywhere in a Table? You can.
To add the div and table stub, open your web page and add the following HTML just above the GridView's tag. Here is the additional HTML followed by complete HTML/ASP for the sample form (in Listing 2).
<div id="fixedHeader" style="position: absolute"> <table id="header" style="position: absolute"> </table> </div>