DHTML Behaviors and THEAD-TBODY-TFOOT Tags
In the January 2004 issue of MSDN Magazine, I demonstrated how to create a DataGrid control with draggable columns and client-side sorting. In doing so, I modified a free DHTML behavior that Dave Massy wrote as the companion code of an old DHTML Dude column for MSDN online.
According to the MSDN Magazine rating system, that article got rave reviews and received excellent feedback. About 12 months later, I can say that readers raised a couple of major issues about the code:
- 1) The DHTML behavior deployed as a separate (and scattered) HTC file
- 2) The necessity of modifying the DataGrid control to make it output extra table tags like THEAD, TBODY, TFOOT.
In the end, using my closing sentences,
A symbiotic relationship between the DataGrid and DHTML can be attained and has lots of advantages for users. But as you can see, it takes a bit of work to coerce the DataGrid into doing everything you want it to do.
Following up to that, a few days ago I took a reader's suggestion about building a DataGrid that allows to move rows up and down on the client and post changes to the server. Once again, I've found a free DHTML behavior to adapt. This time, it is rowover.htc and belongs to the MSDN DHTML Behavior Library. As mentioned, the results will appear in the March 2005 issue of MSDN Magazine.
How did I work around the two aforementioned issues? Let's start with #2.
In ASP.NET 1.1, the Table control only outputs the <table> tag. Similarly, TableRow only manages <tr> tags. If you install a post 1.1 patch for accessibility, TableCell can sometimes morph into <th>. That's all, though. It doesn’t mean you can’t build a fully qualified table, however. You can always make a control output plain text like Write("<thead>").
In ASP.NET 2.0, the Table and related controls have been fixed. So the TableRow class has a property TableSection that indicates where the row belongs to, be it TBODY, THEAD or TFOOT. And the markup is generated accordingly.
row.TableSection = TableRowSection.TableHeader;
As far as Beta 1 is concerned, though, this doesn’t work automatically for grid controls like DataGrid and GridView. The good news is that unlike ASP.NET 1.1 you now have a more effective workaround to apply. In ASP.NET 1.1, the only reliable trick I've been able to find (and readers' post-article suggestions didn't help much) is to output the grid's content to a string and parse to insert missing tags. By moving this code to an output filter, you can perhaps apply changes to all grids automatically, but I don't see significant performance advantages. Some readers suggested to override RenderBeginTag or similar methods. Believe me, no way. The DataGrid delegates to the inner child table control any rendering tasks. And the Table control doesn't support extra tags. Either you replace the whole rendering engine of the DataGrid (challenging, but really worthwhile?) or you do it the way I did.
What's new in ASP.NET 2.0? Because the new TableRow control has a TableSection property you can now successfully override the CreateRow method on a GridView and the CreateItem method on a old-fashioned DataGrid control.
protected override GridViewRow CreateRow(
int rowIndex,
int dataSourceIndex,
DataControlRowType rowType,
DataControlRowState rowState)
{
GridViewRow row;
row = new GridViewRow(rowIndex, dataSourceIndex, rowType, rowState);
switch (rowType) {
case DataControlRowType.Header:
row.TableSection = TableRowSection.TableHeader;
return row;
:
}
}
Neat and elegant, isn't it?
What about #1? To avoid sparse files like HTC files, in ASP.NET 1.1 you can write a custom HTTP handler that retrieves and downloads the resource setting the proper MIME type. Using a HTTP handler requires you to enter a new line to the web.config file and likely a new entry to the IIS metabase if you decide to use a custom extension (not strictly required).
In ASP.NET 2.0, a new system HTTP handler (named WebResource.axd) and the [WebResource] attribute let you retrieve resources from assemblies. WebResource is an assembly-level attribute through which you to mark embedded resources as URL-accessible. You first add the HTC file to the project as an embedded resource and then insert the following code to the AssemblyInfo file of the project:
[assembly: WebResource("Mover.htc", "text/javascript")]
To programmatically access the resource (i.e., to compile the Style property of the control to bind the behavior) you use a new method on the Page class—the GetWebResourceUrl method.
I'll probably cover WebResource in a future post; in the mean time, you can take a look at what one of its authors has to say about it. Handing over to Nikhil. And once again.