Improving the Sort Arrows GridView ControlBy Scott Mitchell
While the GridView control offer built-in, bi-directional sorting support, there is no visual feedback as to what column the data is sorted by. To remedy this shortcoming, I showed how to create a custom server control that extended the
GridViewclass and automatically added arrow up and down images to the appropriate column header, thereby clearly showing what column the data was sorted by and whether the data was sorted in ascending or descending order. Read Extending the GridView to Include Sort Arrows for more information on this technique.
Since publishing that article, I have received a lot of great feedback and suggestions for improving the control. 4Guys reader Richard Deeming proposed
a better technique for adding the arrow images to the appropriate GridView header cell, one that removed the hacks that my approach required. Another
great suggestion came from Tom Mason, who proposed using a differing CSS class in lieu of
<img> elements in the header. Tom's ideas
prompted me to add two new properties to the custom GridView control:
SortDescendingStyle. Use these
properties to customize the appearance of the sorted header cell.
Read on to learn more about these enhancements!
|Please Read Extending the GridView to Include Sort Arrows First|
|If you have not year read the original article, Extending the GridView to Include Sort Arrows, please do so before continuing with this one. The rationale behind designing this control, as well as instructions on how to use the control, are detailed in the original article. This article focuses on the enhancements made since then.|
When to Add the Up/Down Arrow Images
When I first created the custom GridView control, I struggled with where to put the logic to dynamically add the sort arrow images to the appropriate GridView header cell. As noted in Extending the GridView to Include Sort Arrows, my first attempt was to use the GridView's
InitializeRowmethod, but that was not feasible for a number of reasons. I ended up settling on applying the logic in an override of the
Additionally, the way I added the up or down arrow image was less than ideal. I injected the necessary HTML markup directly into the header cell's
HeaderText property. This has two disadvantages:
- Since the
HeaderTextvalue is persisted in view state, the up/down arrow image markup was persisted in view state, as well. Not only did this add a bit of extra bloat to the renderd page's size, but it also necessitated removing the markup. For instance, when a user sorts the results by, say,
ProductName, my code added an
<img>tag to that column's
HeaderText. If the user then sorts the results by
UnitPrice, not only does my code need to add an
<img>tag to the
UnitPricecolumn, but it also needs to remove the
<img>tag from the
- For BoundFields, HTML markup in the
HeaderTextis escaped if the BoundField's
HtmlEncodeproperty is set to True (the default). Consequently, by default the
<img>tag would get escaped to
<img>and show up in the header cell as text. My "solution" was a bit of a hack: I created a custom BoundField control that did not HTML encode the
PrepareControlHierarchymethod that runs every time the GridView is rendered (regardless of whether data has been bound to the control from a data source, or if it was reconstructed from the control's view state) and executes after the GridView's control hierarchy has been built. The purpose of this method is to apply the various styles -
HeaderStyle, and so on - to the Table and TableRows that makeup the GridView's rendered output.
What Richard suggested was that I override this method instead of
OnSorted; moreover, he suggested that instead of squishing in the
markup, that I instead add an Image Web control to the appropriate header cell. What perfect advice! This solves the two problems noted above: by adding
the image as an Image Web control (instead of markup in the
HeaderText property), the Image is not saved in view state, so there's no need
to remove "old" Image controls from other columns. Now, if an item is not saved in view state then it must be added back to the control hierarchy on
every postback. Because the
PrepareControlHiearchy method executes on every postback, we're guaranteed to get the arrow image added
back into the appropriate cell. Furthermore, by using an Image Web control and adding it late in the GridView's lifecycle, we remove the need for a
BoundField class to bypass HTML encoding the header.
To apply these changes, I removed the
BoundField class from the
skmControls2 assembly and commented out the overridden
OnSorted method. I then overrode the
PrepareControlHierachy method and added the following code:
The method starts by calling the base class's
PrepareControlHierarchy method. Next, if there are controls in the GridView's rendered
output and the first row in the
Rows collection is a header row, then the cells in the row are enumerated. If a cell whose
matches the GridView's current
SortExpression is found, then the
CreateSortArrows method is called, passing in the
TableCell that corresponds to the header row cell that the data is sorted by. The
CreateSortArrows method, which we'll examine
in a moment, is responsible for adding the up or down arrow image.
After the arrows have been added, we can exit the
foreach loop since the GridView can be sorted by at most one column.
Before we look at the
CreateSortArrows method, let's discuss the final enhancement I made to the
GridView class - two new
properties for specifying additional style information for the sorted header cell.
Specifying a Style for the Sorted Header Cell
Another suggestion I received for the GridView control came from Tom Mason, who noted that the arrow images can be added entirely using CSS classes rather than
<img>elements. Tom noted that in some of his projects he created the following two CSS classes:
A table cell with the CSS class
GridViewHeaderSortA will display the
arrow-up.gif image as a background. Using Tom's approach,
we could omit adding the up or down arrow and instead just set the cell's
CssClass property to the appropriate CSS class, depending on
whether the column was sorted in ascending or descending order.
This suggestion got me thinking, "Why not allow the user to specify any style settings for the sorted header cell?" Granted, all style information
could (and probably should) be set through a CSS class, but you might want to add a quick and dirty style setting without having to create a CSS class.
To accommodate this, I added two new
TableItemStyle properties to the
class has properties like
CssClass, and can be used to customize
the appearance of the sorted header cell.
The demo available at the end of this article includes an example that sets the
properties of the
SortDescendingStyle properties so that the sorted header cell is shaded differently
from the other cells, and shaded differently if its sorted in ascending or descending order.
Adding the Image and Style to the Sorted Header Cell
As we already discussed, the
PrepareControlHierarchymethod is responsible for locating the header cell that the GridView's data is sorted by (assuming it is sorted). It then passes off this
CreateSortArrowsmethod, which is responsible for adding the sort arrow image and applying the appropriate style. It's code follows:
The method starts by determining whether the data is sorted in ascending or descending order. The arrow image URL and sort style settings depend on the
sort direction. The sort arrow image is added by creating a new Image Web control, settings its
properties, and then adding it to the header cell's
Controls collection. The style information, if specified, has merged in with the header
cell's existing style settings.
The download at the end of this article includes a demo of this custom GridView control in action. The following two screen shots illustrate the use of the two new properties. Note that the sorted column's header cell's colors differ from the non-sorted columns. The header cell for a column sorted in ascending order has a dark purple background.
A yellow background is used when the data is sorted in ascending order.
This article looked at enhancing the custom GridView control initially created in an earlier article, Extending the GridView to Include Sort Arrows. Based on feedback from Richard, I updated the control to use an Image Web control for the up and down arrow images (as opposed to
<img>markup) and moved the logic to add the image to the GridView's
PrepareControlHierarchymethod. Feedback from Tom prompted me to add two new properties to the control -
SortDescendingStyle- which can be used to specify additional style information for the header cell of the sorted column. The complete source code, plus a working demo, are available for download at the end of this article.