March 1, 2021
Hot Topics:

A Better Fixed GridView Header for ASP.NET

  • By Paul Kimmel
  • Send Email »
  • More Articles »

The first ten lines or so beginning with this of var define public members and fields for the PositionClass. As you might expect, you need to store the position and instance of the header as well as the caption, if present. It is these items that you will need to resize (absolutely) if the grid scrolls or the window is scrolled or resized.

Any element that you want to be a public member you need to assign to a local-named element with the this keyword, for instance this.Width = width. Statements like the preceding will introduce an externally accessible member Width (note the capital W) and associate it with variable width (note the lowercase w). This relationship is similar to the field and property relationship in VB. (It is worth noting that JavaScript is case sensitive.)

Because you are defining controls such as a GridView in code-behind, and these controls will generate an HTML table with a specific client-id, it is convenient to store the actual client-id in the PositionClass. setClientID does this. In simple pages, you might hard code the client-id with the identifier given in the code-behind. For example, on a simple page a GridView control with the name GridView1 may actually get a client-id of "GridView1". However, when you build more complicated pages with user controls, you are more likely to get a client-id that includes all of the names of parent controls concatenated together.

The getAbsolutePosition function determines the X or Y position of the header by adding all of the offsets of its parent controls together. The TBODY and TR parent controls are ignored, and this approach seems to yield the best result. The argument getOffset is actually a function argument. It is initialized with either of the functions getXOffset or getYOffset depending on which position—horizontal or vertical—you are resolving. The adjustCaption argument is used to determine whether you should adjust the vertical offset for a top-aligned caption.

The getHeaderNode function walks all of the HTML table rows—the grid rows—to find the row—TR control—containning the table headers—<TH> elements. It is worth noting that you actually could position the real table's row containing table headers. That is, table headers, or any row for that matter, can be positioned absolutely with script regardless of its index in the table. This means that, instead of cloning the table header row and positioning the clone, you could position the original table header row. This is left as an exercise. The challenge with the latter approach is that the fixed table header will overlap row 1 when the grid is scrolled to the top-most row.

The isAligned function checks to see whether the table has a caption and its align property is top, left, right, or blank (""). For all intents and purposes, any of these alignments mean you need to leave room for the caption when positioning a fixed header.

The savePosition function does all of the heavy lifting of storing the present position of the header, cloning it, duplicating its styles, and positioning the cloned-header correctly. Finally, reposition is called when the window (or panel, or anything that scrolls that the grid sits on) scrolls or is resized. This function figures out how far the container was scrolled and adjusts the fixed header accordingly.

Writing an Initialization Function in JavaScript

The final two steps are to write and initialize an invoke function that creates and locates the fixed header and inject a little JavaScript that ensures you have the correct client-id of the grid/table whose header you'd like to fix. Listing 6 shows a function—InitializeFixedHeader—that is not a member of the PositionClass but that will initialize an instance of the PositionClass and bind its behaviors to window events, including onload, onscroll, and onresize.

Listing 6: Initializing the fixed header class, PositionClass.

function InitializeFixedHeader(id)
   var pc = new PositionClass();
   window.onload = pc.SavePosition;
   window.onscroll = pc.Reposition;

Injecting the JavaScript Initialization Code

As you write more complication web applications and reuse user controls, you will need to ensure that the client-id passed to the ID argument in Listing 6 is correct. This can be done easily by injecting some startup script from the code behind. The simple code in Listing 7 demonstrates how you can inject a call to InitializeFixedHeader with the GridView's ClientID property, ensuring the JavaScript id matches the name ASP.NET gives the GridView on the client.

Listing 7: Injecting code to initialize the fixed header.

Protected Sub Page_Load(ByVal sender As Object, _
   ByVal e As System.EventArgs) Handles Me.Load

   Dim Script As String = _
      String.Format("InitializeFixedHeader('{0}');", _

   Page.ClientScript.RegisterStartupScript(Me.GetType(), _
      "fixedHeader", Script, True)

Don't use Response.Write to inject script any longer—if you ever did. The Document Type Definition (DTD) XHML 1.0—the new DTD standard for ASP.NET 2.0—gets wonky and you can get some subtle and annoying behaviors by injecting script with Response.Write.


This sample is long and by no means easy. JavaScript is harder to debug than VB, and it's harder to code correctly because it is syntactically less forgiving. However, JavaScript can add some cool, client-side behaviors to your ASP.NET and VB solutions, so JavaScript (or VBScript) is worth learning. (You will also need JavaScript to make the most of Atlas/Ajax.)

In this article, you learned about object-oriented or object-based JavaScript. And, you learned how to fix a grid header no matter how complicated or nested your pages become. There are shorter techniques—including a previous one that I wrote. These shorter techniques only seem to work on fairly simple pages, though.

About the Author

Paul Kimmel is the VB Today columnist for www.codeguru.com and has written several books on object-oriented programming and .NET. Check out his new book UML DeMystified from McGraw-Hill/Osborne. Paul is a software architect for Tri-State Hospital Supply Corporation. You may contact him for technology questions at pkimmel@softconcepts.com.

If you are interested in joining or sponsoring a .NET Users Group, check out www.glugnet.org. Glugnet is opening a users group branch in Flint, Michigan in August 2007. If you are interested in attending, check out the www.glugnet.org web site for updates.

Copyright © 2007. All Rights Reserved.
By Paul Kimmel. pkimmel@softconcepts.com

Page 4 of 4

This article was originally published on August 29, 2007

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date