Library tutorials & articles

Dynamic Column Sorting and Paging in ASP.NET

Column sorting in an ASP page is a very useful feature giving the user the ability to sort the presented data to their liking, that and can easily be done in one direction by passing the appropriate column sorting order into your query string. But to dynamically and bi-directionally sort is another thing not common and inherent in .NET right out of the box; well unless this is .NET 2.0, which is cool and standard. But since that won't be official for a while, we'll deal with .NET 1.1 in the meantime. At any rate, anyone searching the internet for this kind of functionality will undoubtedly run into quite a few ways of doing this. But I felt I'd just present it in a simple a manner as possible, without any extra hubbub.

I first toyed with the idea of bi-directional and dynamic column sorting and paging back in classic ASP. Good ol' ASP is slightly a little easier to internally manipulate I think in comparison to a .NET Datagrid. A Datareader loop is something similar to a regular ASP standard recordset loop. But a datagrid in .NET is another animal altogether. You can enable sorting and pass into it your chosen field column to sort and the direction, and it'll work like it's supposed to. But what if you needed to constantly resort in the other direction for any given column?

In this article I will demonstrate how to easily do just that, and retain your sort order even when paging. So let's have a look at the entire .NET page.

Let's Get Our Data

<%@ Page Language="VB" Debug="False" Strict="True" Explicit="True" Buffer="True"%>
<%@ Import Namespace="System" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<head>
<title>Dynamic Column Sorting and Paging in ASP.NET</title>
</head>
<body bgcolor="#FFFFFF" topmargin="0" marginheight="0">
<script language="VB" runat="server">
Sub Page_Load (sender As Object, e As EventArgs)
    If SortExp.Text = "" then
        BindSQL ("title asc")
    Else
        BindSQL (SortExp.Text)
    End If
End Sub

Sub BindSQL (SortField As String)
    Dim MyConnection As SqlConnection
    Dim MyCommand As SqlDataAdapter
    Dim DS as Dataset
    Dim sqlStr As String = "SELECT authors.au_fname, authors.au_lname, titles.title, titles.price FROM authors, titleauthor, titles WHERE titleauthor.au_id = authors.au_id AND titleauthor.title_id = titles.title_id ORDER BY title asc"
    Dim strConn As String = "server=(local);uid=sa;pwd=;database=pubs;Trusted_Connection=yes;"
    Dim RcdCount As Integer
    SortExp.Text = SortField
    MyConnection = New SqlConnection(strConn)
    MyCommand = New SqlDataAdapter(sqlStr, MyConnection)
    DS = new Dataset()
    MyCommand.Fill(DS, "pubs")
    Dim Source As DataView = DS.Tables(0).DefaultView
    Source.Sort = SortField
    Pubs.DataSource = Source
    Pubs.Databind()
End Sub

Function SortOrder (Field As String) As String
    Dim so As String = SortExp.Text
    If Field = so Then
        SortOrder = Replace (Field,"asc","desc")
    Else
        SortOrder = Replace (Field,"desc","asc")
    End If
End Function

Sub BookList_Sort (Sender As Object, E As DataGridSortCommandEventArgs)
    pubs.CurrentPageIndex = 0 'To sort from top
    BindSQL (SortOrder (E.SortExpression).ToString()) 'Rebind our Datagrid
End Sub
Sub BookList_PageChange (Source As Object, E As DataGridPageChangedEventArgs)
    pubs.CurrentPageIndex = E.NewPageIndex
    BindSQL (SortExp.Text)
End Sub
</script>
<BR><BR>
<H2>Dynamic Column Sorting and Paging in ASP.NET</H2>
<BR><BR>
<form runat="server">
    <ASP:Datagrid id="Pubs" runat="server"
    Pagesize="10"
    AllowSorting="True"
    AllowPaging="True"
    AllowCustomPaging="False"
    PagerStyle-Visible = "True"
    PagerStyle-Mode = "NumericPages"
    HeaderStyle-BackColor="Blue"
    HeaderStyle-ForeColor="White"
    OnSortCommand="BookList_Sort"
    OnPageIndexChanged="BookList_PageChange"
    AutoGenerateColumns="false"
    >
    <Columns>
        <asp:BoundColumn HeaderText="Title" SortExpression="title asc" DataField="title" Headerstyle-Horizontalalign="Center" ItemStyle-Wrap="false"/>
        <asp:BoundColumn HeaderText="Last Name" SortExpression="au_lname asc" DataField="au_lname" Headerstyle-Horizontalalign="Center" ItemStyle-Wrap="false"/>
        <asp:BoundColumn HeaderText="First Name" SortExpression="au_fname asc" DataField="au_fname" Headerstyle-Horizontalalign="Center" ItemStyle-Wrap="false"/>
        <asp:BoundColumn HeaderText="Price" SortExpression="price asc" DataField="price" Headerstyle-Horizontalalign="Center" ItemStyle-Wrap="false"/>
    </Columns>
    </ASP:DataGrid>
    <asp:Label id="SortExp" runat="server" Visible="False" />
</form>
</body>
</html>

Let's Open Up This Code

To begin with, we imported our namespaces that'll enable us to access our database and retrieve our data. Next we initialize any default actions to be executed upon page load. In this instance we check to see if we have a default sorting order and if we don't we assign it one or simply allow it to accept what's passed in. After that we added our databinding subroutine that'll be called upon to get our data and bind our grid. Now the one new thing that we are accepting is the parameter SortField as String that is passed into our sub, which is going to be the sort order for our columns, and this is pulled from our hidden field located at the end of our page as a label web control. We do of course want to retain the state of our sort across pages when we page our data, so I chose this method among others.

You can opt for alternatives to maintaining state, as there are nine ways in which .NET can accommodate state management. You can read more about user state in - Nine Options for Managing Persistent User State in Your ASP.NET Application. But in this example I chose  the least effortless way to maintain state across postback, and this being our hidden label web control.

<asp:Label id="SortExp" runat="server" Visible="False" />

Now moving on, after dimming our variables I pull in the sort expression that is passed once you click on a column heading. I discuss this process further down. Now, once we connect to our database and fill our datagrid, we now need to create a DataView from our DataSet and pass into it the sort order we want, because without a Dataview this wouldn't be possible. So once we bind our grid and retrieve our data, we can can now choose which column to sort. But how does our datagrid know which column to sort and which order initially?

How we sort the things we do

To begin, we first setup our datagrid properties and make sorting possible by setting Allowsorting to true thereby allowing our column headings to activate and that is how our datagrid will know. We also set Autogeneratecolumns to false so we can determine what columns we prefer to display. To have this happen we need to setup within our datagrid, TemplateColumns , and this is shown below. Notice how a boundcolumn web control is placed within our column tags in our datagrid, and within each BoundColumn is where we want to specify the column and DataField we want to initially display and in this instance the default sorting order we wish to return when the column get's clicked. In our example listed below, we specified a default SortExpression setting of "title asc."

    <Columns>
        <asp:BoundColumn HeaderText="Title" SortExpression="title asc" DataField="title" Headerstyle-Horizontalalign="Center" ItemStyle-Wrap="false"/>
    </Columns>

The additional parameters listed in our Datagrid template columns are Headerstyle-Horizontalalign to align the text in the heading, and ItemStyle-Wrap which is equivalent to the HTML nowrap. Our SortExpression is the default sort order for our respective column, which will kick off our sub and functions, as we'll soon see. Finally in our datagrid we have the crucial event handler OnSortCommand that will trigger our subroutine that does all the magic.

    Sub BookList_Sort (Sender As Object, E As DataGridSortCommandEventArgs)
        pubs.CurrentPageIndex = 0 'To sort from top BindSQL(SortOrder(E.SortExpression))
    End Sub

This sub is called upon by clicking our column heading in our datagird. It first sets our CurrentPageIndex to 0, so our data rebinds from the top, and then binds our grid, and passes into our databind subroutine ( BindSQL ) the appropriate sort order. Now depending on the initial sort order, you'll notice that the BindSQL command has another command - Sortorder . This command calls the SortOrder function , which does the magic, and sends into our BindSQL sub the new sortorder to rebind and resort our datagrid. As you'll now see, it's really pretty simple.

    Function SortOrder (Field As String) As String
    Dim so As String = SortExp.Text
        If Field = so Then
            SortOrder = Replace (Field,"asc","desc")
        Else
            SortOrder = Replace (Field,"desc","asc")
        End If
    End Function

When this function receives its parameter it does two things. It checks to see what was sort order was passed to it, and upon this information returns to the datagrid method the order in which to rebind our grid with.

When we click on any given column, i.e. title, we end up passing into this function "title asc." Once this happens, our function SortOrder checks to see that if title asc has been already passed in by comparing the string passed to it and determine if it's equal with the value in our hidden label web control  SortExp . Otherwise it proceeds to send out to our hidden field the new datagrid sorting order, by replacing the sent sortorder with its reverse. When this is determined the BookList_Sort sub binds the datagrid with the sort order according to the selected column and initial direction or reverse direction if this has been already initially sorted that way, and mission accomplished.

As far as paging is concerned, the built in paging capability in this example doesn't need much explanation. We simply add the necessary datagrid properties to facilitate this, these being:

Pagesize="10"
AllowPaging="True"
AllowCustomPaging="False"
PagerStyle-Visible = "True"
PagerStyle-Mode = "NumericPages"
OnPageIndexChanged="BookList_PageChange"

We set up a default pagesize of 10, allow paging and disabled custom paging . Also we made sure our pager control is visible, and that we want numeric style paging, instead of the left/right arrows. FInally, we added our event handler call when the datagrid paging is activated, in turn calling our BookList_PageChange method, listed below, to handle our paging and rebind our grid with the correct sort order, and that's it.

    Sub BookList_PageChange (Source As Object, E As DataGridPageChangedEventArgs)
        pubs.CurrentPageIndex = E.NewPageIndex 'Set datagrid to current page index
        BindSQL (SortExp.Text) ' Rebind Datagrid with sort order
    End Sub

Although, I have only demonstrated dual directional sorting with standard built in paging, this code can be easily retrofitted to accommodate custom datagrid paging - Custom ASP.NET Datagrid Paging With Exact Count, add Data Caching, set up a Yahoo/Hotmail style Datagrid and even building your very own Full Featured and powerful Custom Datagrid Control that even has drag & drop column capabilities, like the ones you see selling for hundred of dollars!

So instead of bogging the reader (that's you) with too much info, I thought it best to just focus on this one piece of functionality alone, so you can firmly grasp the methodology of it, and leave the process of adding the rest of the bells and whistles up to you.

Conclusion

Well that's really all there is to it in a nutshell. In turn it was all pretty easy, and you ended up giving your users some cool dual sorting and paging capabilities.

Until next time, Happy .NETing.

Comments

  1. 09 Aug 2006 at 15:44
    I usually don't post comments but in this case I feel it's warranted. This was a very useful article. I attempted to use the MSDN example but I usually end up with a headache when I do. Thank-you for posting this information. Code works very well.
  2. 13 Jun 2005 at 12:57

    Hi Ahmed,
      Click Startmenu -> program - > Microsoft Visual Studio 6.0 -> Microsoft Visual Studio 6.0 Tools -> Package & Deployment Wizard. Browse to locate your project for which setup is to be created and click on Package icon. This will take you to "package and deployment wizard - Package type". Select the package type as "Standard Setup package" and click on next button and rest are self explanatory.


    Thanks


  3. 10 Jun 2005 at 17:47

    hi
    i have to submit my project on 20th of this month i have made it but the thing which is left is that i want to make a setup file of the whole project like the one of MSN messenger... i think to might have understood what i wana say...


    i want to deliever the project setup file... can u help me do reple on ahmed_muneeb@hotmail.com


    in the setup file i want that the connectivity is done automatically and i dont have to bring my PC along...


    i have used VB 6.0 and access...... for database....


    thanks

  4. 10 Jun 2005 at 17:34

    Hey acurra79,


    Nice catch! Clearly an oversight. Thanks. I have corrected the C# code and the article as well.


    - Jimmy Markatos

  5. 10 Jun 2005 at 09:38

    Hi,


    I notice the following error when I try to run the code:


    When you navigate to the second, third, etc page (order by ASC only), the sorting order is incorrect.
    This is because the SortOrder function change the direction from asc to desc.


    To correct this error, change the the line:


    BindSQL(SortOrder(SortExp.Text));


    TO


    BindSQL(SortExp.Text);

  6. 03 May 2005 at 22:51

    Hi all,


    For all you C# coders out there, I've included the article's code in C# to save anyone the headache of converting it.


    Code:

    <%@ Page Language="C#" Debug="False" Strict="True" Explicit="True" Buffer="True"%>
    <%@ Import Namespace="System" %>
    <%@ Import Namespace="System.Data" %>
    <%@ Import Namespace="System.Data.SqlClient" %>
    <html>
    <head>
    <title>Dynamic Column Sorting and Paging in ASP.NET</title>
    </head>
    <body bgcolor="#FFFFFF" topmargin="0" marginheight="0">


    <script language="C#" runat="server">
    void Page_Load (Object sender, EventArgs e) {


       if(SortExp.Text == ""){
           BindSQL ("title asc");
       } else {
           BindSQL (SortExp.Text);
       }


    }


    void BindSQL (string SortField) {
       SqlConnection MyConnection;
       SqlDataAdapter MyCommand;
       string sqlStr = "SELECT authors.aufname, authors.aulname, titles.title, titles.price FROM authors, titleauthor, titles WHERE titleauthor.auid = authors.auid AND titleauthor.titleid = titles.titleid ORDER BY title asc";
       string strConn = "server=(local);uid=sa;pwd=;database=Pubs;";
       int RcdCount;


       SortExp.Text = SortField;


       MyConnection = new SqlConnection(strConn);
       MyCommand = new SqlDataAdapter(sqlStr, MyConnection);
       DataSet DS = new DataSet();
       MyCommand.Fill(DS, "Pubs");
       DataView Source = DS.Tables[0].DefaultView;
       Source.Sort = SortField;
       Pubs.DataSource = Source;
       Pubs.DataBind();
    }


    string SortOrder (string Field) {
       string so = SortExp.Text;
       string newString;


       if (Field == so) {
           newString = Field.Replace ("asc","desc");
       }else {
           newString = Field.Replace ("desc","asc");
       }
       return newString;
    }


    public void BookList_Sort (Object Sender, DataGridSortCommandEventArgs E) {
       Pubs.CurrentPageIndex = 0; //To sort from top
       BindSQL (SortOrder (E.SortExpression).ToString()); //Rebind our Datagrid
    }


    public void BookListPageChange (Object Source, DataGridPageChangedEventArgs E) {
       Pubs.CurrentPageIndex = E.NewPageIndex;
       BindSQL(SortExp.Text);
    }
    </script>
    <BR><BR>
    <H2>Dynamic Column Sorting and Paging in ASP.NET</H2>
    <BR><BR>
    <form runat="server">
       <ASP:Datagrid id="Pubs" runat="server"
       Pagesize="10"
       AllowSorting="True"
       AllowPaging="True"
       AllowCustomPaging="False"
       PagerStyle-Visible = "True"
       PagerStyle-Mode = "NumericPages"
       HeaderStyle-BackColor="Blue"
       HeaderStyle-ForeColor="White"
       OnSortCommand="BookList
    Sort"
       OnPageIndexChanged="BookListPageChange"
       AutoGenerateColumns="false"
       >
       <Columns>
           <asp:BoundColumn HeaderText="Title" SortExpression="title asc" DataField="title" Headerstyle-Horizontalalign="Center" ItemStyle-Wrap="false"/>
           <asp:BoundColumn HeaderText="Last Name" SortExpression="au
    lname asc" DataField="aulname" Headerstyle-Horizontalalign="Center" ItemStyle-Wrap="false"/>
           <asp:BoundColumn HeaderText="First Name" SortExpression="au
    fname asc" DataField="au_fname" Headerstyle-Horizontalalign="Center" ItemStyle-Wrap="false"/>
           <asp:BoundColumn HeaderText="Price" SortExpression="price asc" DataField="price" Headerstyle-Horizontalalign="Center" ItemStyle-Wrap="false"/>
       </Columns>
       </ASP:DataGrid>
       <asp:Label id="SortExp" runat="server" Visible="False" />
    </form>
    </body>
    </html>



    - Jimmy Markatos

  7. 01 Jan 1999 at 00:00

    This thread is for discussions of Dynamic Column Sorting and Paging in ASP.NET.

Leave a comment

Sign in or Join us (it's free).

Dimitrios Markatos Dimitrios, or Jimmy as his friends call him, is a .NET developer/architect who specializes in Microsoft Technologies for creating high-performance and scalable data-driven enterprise Web and deskto...
AddThis

Related podcasts

Want to stay in touch with what's going on? Follow us on twitter!