You are here: Home > Articles > Article Display

Maintaining Sorting while Paging in an ASP.NET Datagrid

The Datagrid server control offers much control and flexibility in presenting data. Two of the actions that are hard-wired into it are Paging and Sorting. On their own they work great, but not so well together. When you sort a column and then move to a previous or next page, the sorting preference is not maintained. In this article we will see how to maintain both by using the Viewstate object.

Published: Dec 18, 2002
Tested with: ASP.NET 1.1
Category: ASP.NET
27,804 views

Introduction

The Datagrid server control offers much control and flexibility in presenting data. Two of the actions that are hard-wired into it are Paging and Sorting. On their own they work great, but not so well together. When you sort a column and then move to a previous or next page, the sorting preference is not maintained. In this article we will see how to maintain both by using the Viewstate object.

Creating the interface for our Datagrid

The idea behind this article came after trying to display this site's articles in a Datagrid. I was able to get lots of help from an article by Bipin Joshi, a good read and the basis for the code to follow. I am going to use a simple MS Access file, with only one table inside it for demonstration purposes. The table, article, is made of 5 fields:

Design view of table Article in Access

This table includes basic information about some of the articles on this site. This Access file is included in the downloadable material for this article. After we enter some data into the table, let's see how to display it in a Datagrid.

1 <form runat="server" method="post">
2 <asp:Datagrid runat="server"
3     Id="MyDataGrid"
4     GridLines="Horizontal"
5     AutoGenerateColumns="false"
6     BorderColor="#CCCCCC"
7     CellPadding="7"
8     CellSpacing="0"
9     AllowPaging="true"
10     OnPageIndexChanged="PageGrid"
11     AllowSorting="true"
12     OnSortCommand="SortGrid"
13     BorderWidth="1"
14     PageSize="5">
15     <headerstyle
16         Font-Name="Tahoma"
17         Font-Size="84%"
18         Font-Bold="true"
19         BackColor="#CCCCCC">
20     </headerstyle>
21     <itemstyle
22         Font-Name="Verdana"
23         Font-Size="70%"
24         VerticalAlign="top"
25         BackColor="#FFFFFF">
26     </itemstyle>
27     <alternatingitemstyle
28         BackColor="#FFFFFF">
29     </alternatingitemstyle>
30     <pagerstyle
31         Position="Top"
32         Mode="NumericPages"
33         HorizontalAlign="Center"
34         BackColor="#FFFFD9">
35     </pagerstyle>
36 ...

Our Datagrid has an ID of MyDataGrid. We turn off AutoGenerateColumns, so that we have to bind each column individually. We set AllowSorting to True, and the method to run on sort is SortGrid(). We also allow paging and the custom method to run on changing pages is PageGrid().

We then proceed in customizing the look of the Header, each item (line) that shows up in our Datagrid, each alternating item, and finally the Pager - which includes our standard buttons for moving between pages.

Finally, let's bind the columns to the Datagrid:

1 ...
2     <columns>
3         <asp:TemplateColumn>
4             <headertemplate>
5                 Title and Description
6             </headertemplate>
7         <ItemTemplate>
8             <b><%# DataBinder.Eval(Container.DataItem, "title") %></b><br>
9             <%# DataBinder.Eval(Container.DataItem, "description") %><br>
10             <a href="<%# DataBinder.Eval(Container.DataItem, "url") %>">
11             Read More...</a>
12         </ItemTemplate>
13     </asp:TemplateColumn>
14     <asp:boundColumn
15         DataField="posted"
16         SortExpression="posted"
17         HeaderText="Posted on"
18         DataFormatString="{0:d MMM yyyy, dddd}"
19         ItemStyle-Wrap="false">
20     </asp:boundColumn>
21     </columns>
22 </asp:DataGrid>
23 </form>

Binding our Datagrid

Our database query is going to look something like this: "SELECT title, description, url, posted FROM article ORDER BY posted DESC". The most important part in the query is what follows after the ORDER BY. We are going to make this dynamic, and use the Viewstate object to remember what we are sorting by and in what order. We will create 2 Viewstate objects:

  1. viewstate("sortField") - what field to sort by
  2. viewstate("sortDirection") - ASC or DESC

Our query can now become more dynamic: "SELECT title, description, url, posted FROM article ORDER BY " & viewstate("sortField").ToString() & " " & viewstate("sortDirection").ToString().

I am not going to cover what a Viewstate is. If you are interested, you can take a closer look at it.

Now that we have seen how to make our query dynamic, let's look at the code to do this. First, we need to import the necessary libraries to work with our database:

1 <%@ Page language="vb" runat="server" explicit="true" %>
2 <%@ Import Namespace="System.Data" %>
3 <%@ Import Namespace="System.Data.OleDB" %>
4 ...

Our default Page_Load() method will simply check if the page is not posting back to itself. If it is not, it will set the 2 viewstates to some default values and call our custom BindGrid() method to perform our database connection, query and databind. When the page posts back to itself, there is no need to explicitly call the binding: it will be done automatically.

1 ...
2 <script language="vb" runat="server">
3 Private Sub Page_Load(sender As Object, e As EventArgs)
4     If Not Page.IsPostBack Then
5         viewstate("sortField") = "posted"
6         viewstate("sortDirection") = "DESC"
7         BindGrid()
8     End If
9 End Sub
10
11 Private Sub BindGrid()
12     Dim strConn As string = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath("/database/articles.mdb") & ";"
13     Dim MySQL As string = "SELECT title, description, url, posted FROM article ORDER BY viewstate("sortField").ToString() & " " & viewstate("sortDirection").ToString()
14     Dim MyConn As New OleDBConnection(strConn)
15     Dim ds As DataSet = New DataSet()
16     Dim Cmd As New OleDBDataAdapter(MySQL,MyConn)
17     Cmd.Fill(ds,"Articles")
18     Try
19         MyDataGrid.DataSource = ds
20         MyDataGrid.Databind()
21     Catch e As Exception
22         MyDataGrid.CurrentPageIndex = 0
23     End Try
24 End Sub
25 ...

Remember that in setting up our Datagrid, we asked it to perform a custom method called PageGrid() upon changing pages. When we click on the page number to go to, the Datagrid is posted back to itself, implementing the DataGridPageChangedEventArgs. Part of them is the page number we want: NewPageIndex. We take this number and assign it to the current page of the Datagrid before we bind it.

1 ...
2 Private Sub PageGrid(ByVal source As Object, ByVal e As DataGridPageChangedEventArgs)
3     MyDataGrid.CurrentPageIndex = e.NewPageIndex
4     BindGrid()
5 End Sub
6 ...

Finally, we have our sorting method: SortGrid(). When we click on a column it sends the SortExpression value of that column back to the server, which is implemented through the DataGridSortCommandEventArgs. In our example, this translates to the value of "posted" being sent when we click on the "Posted on" column. You can add more columns if you like, just make sure you are sending the correct expression back to the server.

This method sets our viewstates. The logic is simple. When we click on a column to sort by, we want to check if we are already sorting by that column. If we are not, then we simply set that new column as the field to sort by, and set the direction to sort by as DESC. If however, we are already sorting by the same column, then we switch the sorting order: from ASC to DESC and vice versa.

1 ...
2 Private Sub SortGrid(ByVal source As Object, ByVal e As DataGridSortCommandEventArgs)
3     If e.SortExpression.ToString() = viewstate("sortField").ToString() Then
4         Select Case viewstate("sortDirection").ToString()
5             Case "ASC"
6                 viewstate("sortDirection") = "DESC"
7             Case "DESC"
8                 viewstate("sortDirection") = "ASC"
9         End Select
10     Else
11         viewstate("sortField") = e.SortExpression
12         viewstate("sortDirection") = "DESC"
13     End If
14     BindGrid()
15 End Sub

Now when you try to sort the columns by ASC or DESC order, and then navigate to a different page, you will notice that the Datagrid remembers your sorting order. If you'd like, you can download the Access database and the ASPX file that connects to it from the top of this page. Unzip them anywhere on your site in the same folder, and you are ready to go.

Conclusion

Using the Viewstate is a nice way of maintaining bidirectional sorting in the Datagrid. It's also possible to use Sessions, in pretty much the same way. We would just replace every occurence of viewstate([variable]) with Session([variable]), and it would work the same way. The Viewstate is a better way of doing it though. If we wanted, we could customize the sorting coluns to display an icon as well, showing the direction we are sorting by.

 



Other articles in this category
  1. Smart headers and footers using ASP.NET User Controls
    December 23, 2002
    Good site usability often means removing links from one page back to itself. In this article we will look at how to create an ASP.NET User Control which will act as a common header to a site. It will automatically know which page we are looking at, and it will remove links to the same page from itself. For example, on this site, if we click on the About us section of the header, it will take you to the page, and it will make that link inactive. That way, we know that we are under that section, and we can't click on it anymore.
  2. How postback works in ASP.NET
    December 10, 2002
    In this article, we will take a closer look at how ASP.NET pages post back to themselves, and how to customize this feature in our web applications.
  3. Viewing and editing file and directory attributes in ASP.NET
    December 2, 2002
    The System.IO.FileAttributes class gives us access to file/directory attributes. In this article, we'll see how to use this class to first read the current attributes and then change them.
  4. Copying a directory in ASP.NET
    November 25, 2002
    The System.IO.DirectoryInfo class does not come with a method to copy a directory. In this article, we'll see how to create a method to do that, and then use it in an ASP.NET page.
  5. Creating and consuming a Web Service using Visual Studio .NET
    November 18, 2002
    This article will go through the complete process of how to create a Web Service and then how to consume it in any ASPX page. We'll do this entirely within the Visual Studio.NET. Our Web Service will convert Fahrenheit degrees to Celcius.