Tip 8: Sorting Using the ASP.NET 2.0 GridView
In Tip 6 you built a basic GridView, set the
AllowSorting and
AllowPaging properties to
true, and defined the
SortExpression for each databound column. When you run that GridView in a Web browser each column heading displays as a link that you can click on to sort the grid by that column. You'll also see links at the bottom of the grid (caused by the
AllowPaging property) to navigate to another page, if the bound dataset contains more rows than can fit on a single page.
Unfortunately, when you click either of those links, things don't go as planned and you'll actually receive nasty runtime error messages (see
Figure 5 and
Figure 6).
 | |
Figure 5: Error message before the Sorting event. |
|
 | |
Figure 6: Error message before we handle the PageIndexChanging event. |
|
|
So what's wrong? As the messages indicate, you need to add some code to the GridView's
Sorting and
PageIndexChanging events for the operations to work correctly. Because these events fire as part of a postback, you need to take a step back and look at your approach.
In both the
Sorting event and
PageIndexChanging event, essentially you'll need to access the GridView's
DataSource property and modify the sort expression for the
DataSource.DefaultView property. However, as you look back to the basic code in Tip 6, you aren't storing the data source in any way that you can access it. So before you implement any custom sorting and paging code, you need to address this.
You may choose to store the GridView's
DataSource value in the ViewState as a property, like so.
DataTable dtOrders
{
get { return (DataTable)ViewState["dtOrders"]; }
set { ViewState["dtOrders"] = value; }
}
However, if you have a fairly large result set, that means the page must carry the entire list of orders in the ViewState. (To see this, set up a Web page, store the result set in the ViewState, run the page, and click "View
.Source." The volume of data might be more than you bargained for!) In addition, not all datatypes will serialize. For instance, you cannot store a DataRow object in this manner.
Alternatively you could store the DataSource in a session variable, at the time the databinding is performed. So to revisit the code snippet from Tip 6:
DataSet dsData = this.GetData();
// Run whatever process you want, for the query
// SELECT OrderID, CustomerID, OrderDate,
// ShippedDate, Freight FROM Orders ORDER BY
// OrderID
this.grdOrders.DataSource = dsData.Tables[0];
// Store the datatable as a Session Variable
Session["dtOrders"] = dsData.Tables[0];
this.grdOrders.DataBind();
Now that you're storing the DataSource in the session, you can access the Session variable in the
Sorting event and modify the
SortExpression of the data source's
DefaultView accordingly. Note that the
SortExpression comes from the
SortExpression property that you initially defined for the column.
protected void grdOrders_Sorting
(object sender, GridViewSortEventArgs e)
{
DataTable dtOrders =
(DataTable)Session["dtOrders"];
if (dtOrders != null) {
dtOrders.DefaultView.Sort = e.SortExpression
this.grdOrders.DataSource = dtOrders.DefaultView;
Session["dtOrders"] = dtOrders;
this.grdOrders.DataBind();
}
}
Note that the above technique isn't either new or earth-shatteringyou can find the same or similar approach on dozens of different ASP.NET forums.
Tip 9: Paging Using the ASP.NET 2.0 GridView
Now that you've tackled the sorting, you can address the paging. When the user clicks on one of the page links at the bottom of the page, a postback occurs and the
PageIndexChanging event fires. You can determine the page the user selected from the
GridViewPageEventArgs parameter, and use that value to set the GridView's
PageIndex. Note that to retain any sorting that might have been done, you need to access the
DefaultView property of the GridView's DataSource.
protected void grdOrders_PageIndexChanging
(object sender, GridViewPageEventArgs e)
{
// must set new PageIndex and rebind
this.grdOrders.PageIndex = e.NewPageIndex;
this.grdOrders.DataSource =
((DataTable)Session["dtOrders"]).DefaultView;
this.grdOrders.DataBind();
}
Before you move on, a word about Session variables. Some people use them, some don't: some love them and swear by them, some argue against them for scalability issues, and some are in between.
Session variables are very easy, almost
too easy to use. And of course, anything that is very easy to use can often be abused. The October 2003 issue of
Visual Studio Magazine has an outstanding article by Leonard Lobel on managing session state. The article covers seven server-side state management techniques, including storing session information in SQL Server. If you want to learn more about this topic, you will greatly benefit from what Mr. Lobel has to say.