An Extensive Examination of the DataGrid Web Control: Part 18
By Scott Mitchell
The 18th Part in a Multi-Part Series
This article is the eighteenth piece of a multi-part series on using the DataGrid Web control that will span
several months. The ASP.NET DataGrid Web control, which displays database information in an HTML table, is
highly versatile. The basics of the DataGrid were discussed in Part 1;
information on specifying display properties of the DataGrid was discussed in
Part 2. In Part 3
we examined how to associate custom events with the DataGrid.
In Part 4 we looked at how to extend
Part 3 to provide custom sorting on the results of a DataGrid. In
Part 5 we examined how to use templates to further customize
the DataGrid's appearance. Part 6 examined how to use the
DataGrid's built-in editing capabilities, while Part 7 looked at
customizing the editing interface using the EditItemTemplate. In Part 8
we looked at how to add client-side code to a ButtonColumn's client-side onclick event.
In Part 9 we examined how to enhance the DataGrid's editing
interface by having the editing interface's TextBox receive focus when the page is loaded.
In Part 10 we looked at how to (automatically) add filtering
buttons so that one can filter the data in a DataGrid. In Part 11
we examined how to create a DataGrid Web control with a column of related radio buttons.
In Part 12 we examined how to create a sortable DataGrid
that can be sorted in ascending and descending order. Part 13
examined how to sum up a DataGrid column and have the sum displayed in the footer. Part
14 looked at how to build a master/detail DataGrid. Part 15 looked at
adding paging support to a DataGrid. Part 16 examined how to create an editable
DataGrid with two data-dependent DropDownLists. Part 17 looked at building a
fully-editable DataGrid. In this eighteenth part we'll examine an alternative approach for creating a bi-directional sortable
DataGrid and see how to gussy up the DataGrid to include up and down arrows in the sorted column.
ASP.NET Data Web Controls Kick Start is author Scott
Mitchell's most recent book, which thoroughly examines three of the most commonly
used ASP.NET Web controls: the DataGrid, DataList, and Repeater. These three Web controls
can be difficult to master due to their numerous features and capabilities. With this book, you'll
quickly become an expert, learning the gritty details and true capabilities of each.
This 400+ page book explores the topics in this article series in much greater depth, along with
examining various topics and techniques not covered here.
Scott Mitchell is the editor and founder of 4GuysFromRolla.com, author of the An Extensive Examination
of the DataGrid Web Control article series, and author of numerous other ASP and ASP.NET
books.
Introduction
The DataGrid Web control includes a bevy of common features, such as paging, sorting, and row-by-row editing of the DataGrid's
underlying data. We've discussed how to accomplish these tasks in previous installments of the
An Extensive Examination of the DataGrid Web Control article series, first looking
at creating a sortable DataGrid in Part 4. Unfortunately the DataGrid's built-in sorting
only allows for uni-directional sorting. That is, when creating the DataGrid you must decide on a column-by-column basis
if the data will be sorted in ascending or descending order.
While it's impressive the ease with which uni-directional sorting can be added to a DataGrid, ideally we'd like to offer
bi-directional sorting. There are a couple of techniques that can be used to accomplish this end, one of which was discussed
in Part 12 of this article series. Specifically, Part 12 showed how to dynamically
adjust each DataGrid column's SortExpression property to toggle ascending or descending sorting. One downside
of this approach, as Part 12 noted, was that you needed to hard-code in sortable column, mapping the SortExpression
to the appropriate DataGridColumns index. This downside of this approach, then, is that it would need to be customized
for each page that you wanted to use a bi-directional sortable DataGrid.
In this 18th part of the An Extensive Examination of the DataGrid Web Control article series we'll look at an alternative
approach to implementing bi-directional sorting, one that doesn't require any hard-coded mapping and therefore can easily
be reused. We'll also look at a simple method that will enhance the appearance of our bi-directional sortable DataGrid,
adding little up and down arrows on the column header that the grid's data is sorted by. Read on to learn more!
(If you are unfamiliar with creating a sortable DataGrid, please take a moment to first read Part 4
of this article series before continuing; if you have never created a bi-directional sortable DataGrid, be sure to
read Part 12 before tackling this part.)
Storing Sorting Information in the ViewState
As you know, in a sortable DataGrid each sortable column has a SortExpression property that is passed to the
DataGrid's SortCommand event handler when that particular column's sort heading is clicked. Typically the
SortExpression will contain the actual SQL syntax that you want to have injected into the ORDER BY
clause. For example, imagine that you were showing employee information in a DataGrid using BoundColumns to display the
database fields Name, Salary, and HireDate. In the Salary DataGrid column you could
simply use a SortExpression of Salary (or Salary ASC), which would indicate that you want to sort the column
by the Salary field in ascending order. If you wanted to sort by salary in descending order you'd simply use
Salary DESC as the SortExpression.
This technique works well for creating uni-directional sortable DataGrids. For bi-directional sortable DataGrids, however,
we need to be able to dynamically add the DESC or ASC depending on whether or not we want to
now sort in ascending or descending order. Part 12 of this article series looked at
one technique to implement a bi-directional sortable DataGrid. Specifically, Part 12's logic checked the SortExpression
property in the SortCommand event handler. If it ended with ASC it changed the clicked DataGrid column's
SortExpression, replacing the ASC with DESC; similarly, if the SortExpression
already ended with DESC it was replaced with ASC. While this approach definitely worked, one downside
was that in order to set the correct DataGrid column's SortExpression we needed to provide a mapping from the
SortExpression property passed in and the corresponding index in the DataGrid's Columns collection.
With this hard-coded mapping, the code would have to be customized for each bi-directional sortable DataGrid you created.
A better approach, in my opinion, and the technique I discuss in my book ASP.NET
Data Web Controls Kick Start, is to use the ViewState to track both the column to sort by and the direction. This technique
involves maintaining two page-level properties which I usually name SortExpression (a string) and SortAscending
(a Boolean). These two properties simply use the ViewState StateBag as their backing store (thereby ensuring that
the values are remembered across postbacks). Then, in my SortCommand event handler I first check to see if the
column the data is currently sorted by has already been clicked again. If so, I toggle the SortAscending property,
thereby changing the sort direction. I finish by setting the SortExpression property maintained in ViewState to the
SortExpression value passed into the SortCommand event handler.
'The Page-level properties that write to ViewState
Private Property SortExpression() As String
Get
Dim o As Object = viewstate("SortExpression")
If o Is Nothing Then
Return String.Empty
Else
Return o.ToString
End If
End Get
Set(ByVal Value As String)
viewstate("SortExpression") = Value
End Set
End Property
Private Property SortAscending() As Boolean
Get
Dim o As Object = viewstate("SortAscending")
If o Is Nothing Then
Return True
Else
Return Convert.ToBoolean(o)
End If
End Get
Set(ByVal Value As Boolean)
viewstate("SortAscending") = Value
End Set
End Property
'The SortCommand event handler
Private Sub dgPActivities_SortCommand(ByVal source As Object, _
ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) _
Handles dgPActivities.SortCommand
'Toggle SortAscending if the column that the data was sorted by has
'been clicked again...
If e.SortExpression = Me.SortExpression Then
SortAscending = Not SortAscending
Else
SortAscending = True
End If
'Set the SortExpression property to the SortExpression passed in
Me.SortExpression = e.SortExpression
BindData() 'rebind the DataGrid data
End Sub
The BindData() method contains the code that grabs the appropriately-sorted data from the database and binds
it to the DataGrid. See Parts 4 or 12 for a description of the BindData() method for a sortable DataGrid.
Improving the Appearance of the Bi-Directional Sortable DataGrid
At this point we have a working bi-directional sortable DataGrid, however there are no visual cues to indicate how the
data is sorted. Many websites that offer bi-directional sortable data display a little arrow or icon next to the column that
the data is sorted by. What I'd like to show is a simple method that will add a little up or down arrow next to the sorted
column, depending on whether the column sorted by is sorted in ascending or descending order.
The following method, UpdateColumnHeaders(DataGrid), takes in as input a DataGrid and iterates through
its Columns collection, looking for the DataGrid column by which the data is sorted. Once it finds that DataGrid
column is adds to it an image tag of either an up or down arrow, depending on if the data is sorted in ascending or
descending order. (The up and down arrows I use in the live demo can be downloaded
here: http://aspnet.4guysfromrolla.com/images/up.gif and
http://aspnet.4guysfromrolla.com/images/down.gif.) Before
adding the up or down arrow, a regular expression is used to strip out any image tag markup that might be present.
Sub UpdateColumnHeaders(ByVal dg As DataGrid)
Dim c As DataGridColumn
For Each c In dg.Columns
'Clear any <img> tags that might be present
c.HeaderText = Regex.Replace(c.HeaderText, "\s<.*>", String.Empty)
If c.SortExpression = SortExpression Then
If SortAscending Then
c.HeaderText &= " <img src=""/images/up.gif"" border=""0"">"
Else
c.HeaderText &= " <img src=""/images/down.gif"" border=""0"">"
End If
End If
Next
End Sub
To use this method simply call it from the BindData() method prior to binding the data to the DataGrid.
(See the live demo for a complete, working code example.)
Adding Up and Down Arrows Images for the ASP.NET 2.0 GridView Control
For those of you using ASP.NET 2.0, you'll be happy to
know that I've written an article showing how to add these up and down arrow images for a sortable
GridView. For more information, see: Extending
the GridView to Include Sort Arrows.
Conclusion (and Making this Approach Reusable)
In this article we examined an alternative approach for building a bi-directional sortable DataGrid, one that uses two
ViewState-backed Page properties to keep track of the column to sort by and whether the data should be sorted in ascending or
descending order. Along with this we looked at a simple, generic method that can be called to add an up or down arrow in the
DataGrid column by which the data is sorted.
At the beginning of this article I mentioned my preference for using ViewState to implement a bi-directional sortable DataGrid
because it keeps the code for implementing the sort functionality loosely coupled from the data being bound to the DataGrid
(whereas the approach discussed in Part 12 had the information tightly bound). Furthermore,
the astute reader will notice that I made the UpdateColumnHeaders(DataGrid) generic as well - that is, it
will work with any DataGrid you pass in, there's no coupling between the code and the specifics of a DataGrid.
Given this
you could easily move the sorting properties and UpdateColumnHeaders(DataGrid) method to a custom base class.
If you have a page, then, that needs to provide a bi-directional sortable DataGrid you simply have that page inherit from the
custom base class page. With a bit of refactoring of the BindData() method and SortCommand event handler
you could end up with a means to create a bi-directional sortable DataGrid with just a couple lines of code. I leave this migration
to a base class and the necessary refactoring as an exercise for the interested reader. (For more information on custom base
classes be sure to read Using a Custom Base Class for your ASP.NET Page's Code-Behind Classes.)