Custom Sorting with N-Layer Design Classes and the GridView

Over the past couple of months I received a number of questions related to sorting with the classes from my N-Layer Design article series and the GridView. The good thing is: it isn't that hard; it's just that you need to know how to do it....

Prerequisites

The code presented in this short article replaces the code for the ContactPersonManager.cs file in the BusinessLogic folder of the N-Layer Design application. If you haven't read the article series yet, please read them first, or otherwise you probably won't have a clue where this is all about. Simply copy it over the existing file and you're good to go. If you rather not copy over the entire file, then you need to look at two things: first, the GetList method in ContactPersonManager.cs has changed and now accepts a string parameter called sortExpression and secondly the class now has an additional region with a nested class called ContactPersonComparer that takes care of sorting.

The file TestSorting.aspx that also comes with this article's download is a very simple ASPX file with a simple GridView that demonstrates how to apply sorting. Take a look at the GridView and the connected ObjectDataSource first:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
       DataKeyNames="Id" DataSourceID="ObjectDataSource1" AllowSorting="True">
  <Columns>
    <asp:BoundField DataField="LastName" HeaderText="LastName" 
          SortExpression="LastName" />
    <asp:BoundField DataField="Id" HeaderText="Id" 
          InsertVisible="False" ReadOnly="True" SortExpression="Id" />
    <asp:BoundField DataField="FirstName" HeaderText="FirstName" 
          SortExpression="FirstName" />
    <asp:BoundField DataField="MiddleName" HeaderText="MiddleName" 
          SortExpression="MiddleName" />
    <asp:BoundField DataField="DateOfBirth" HeaderText="DateOfBirth" 
          SortExpression="DateOfBirth" />
  </Columns>
</asp:GridView>

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" 
      SortParameterName="sortExpression" SelectMethod="GetList"
      TypeName="Spaanjaars.ContactManager.Bll.ContactPersonManager">
</asp:ObjectDataSource>

This all looks like a normal GridView and ObjectDataSource with one exception: the SortParameterName attribute on the ObjectDataSource:

SortParameterName="sortExpression"

This tells the ObjectDataSource to forward the selected SortExpression it receives from the GridView (when you click on the column headers) to the GetList method. I modified the GetList method slightly and it now accepts an additional sortExpression parameter:

public static ContactPersonList GetList(string sortExpression)
{
  ContactPersonList myList = ContactPersonDB.GetList();
  myList.Sort(new ContactPersonComparer(sortExpression));
  return myList;
}			

Notice how the sortExpression parameter is sent to the constructor of ContactPersonComparer class. The ContactPersonComparer instance in turn is sent to the Sort method on the generics List which handles sorting for you. Whenever the Sort method needs to compare two objects, it'll ask the ContactPersonComparer object how to do it. That object does that with the Compare method you'll find in the nested ContactPersonComparer class inside the file ContactPersonManager.cs. The compare method looks like this:

public int Compare(ContactPerson a, ContactPerson b)
{
  int retVal = 0;
  switch (_sortColumn.ToLower())
  {
    case "id":
      retVal = a.Id.CompareTo(b.Id);
      break;
    case "firstname":
      retVal = a.FirstName.CompareTo(b.FirstName);
      break;
    case "lastname":
      retVal = a.LastName.CompareTo(b.LastName);
      break;
    case "middlename":
      retVal = a.MiddleName.CompareTo(b.MiddleName);
      break;
    case "dateofbirth":
      retVal = a.DateOfBirth.CompareTo(b.DateOfBirth);
      break;
  }
  int _reverseInt = 1;
  if ((_reverse))
  {
    _reverseInt = -1;
  }
  return (retVal * _reverseInt);
}

This method accepts two ContactPerson instances and then returns an int to indicate whether the left hand side or the right hand side is "greater" than the other. Basically, it leaves it to the individual property's CompareTo methods to determine which of the two is bigger. It uses the private _sortColumn variable to determine on what property to sort. _sortColumn is set in the class's constructor like this:

public ContactPersonComparer(string sortExpression)
{
  if (sortExpression.Length == 0)
  {
    sortExpression = "Id desc";
  }
  _reverse = sortExpression.ToLowerInvariant().EndsWith(" desc");
  
  if (_reverse)
  {
    _sortColumn = sortExpression.Substring(0, sortExpression.Length - 5);
  }
  else
  {
    _sortColumn = sortExpression;
  }
}

The GridView keeps track of the sort column and the direction in which you want to sort (ascending or descending). You don't need to do anything to enable this two-way sorting mechanism. For example, the first time you click the Id header, the sortExpression will be "Id". This is sent to the ObjectDataSource which forwards it to the GetList method and eventually it ends up in the ContactPersonComparer's constructor. Since it simply contains "Id", nothing special is done with the value, and _sortColumn will simply be "Id". However, the second time you click the heading, the sortExpression will be "Id DESC" to indicate you want to sort in reverse order. In this case, _reverse is set to true and DESC is stripped from the sortExpression. The variables _sortColumn and _reverse are then used again in the Compare method to determine if one ContactPerson is "greater" than another.

Summary

Sorting is pretty easy with collections like the generics List class. You don't need to order items in the list manually or find out what item should be on top or at the bottom of the list. Instead, you need to create a class that implements IComparer<T> where T is the class you want to order on, like IComparer<ContactPerson>.

Once you have the class in place, you can copy the boilerplate code for the constructor as it's always the same code. The only thing you need to do is write case statements for the various properties of the sorted object. Note that you're not limited to simple properties. If you want, you could sort on things like the number of address in the Addresses collection if you wanted to.

Download Files

Download the modified files that demonstrate sorting

Where to Next?

Wonder where to go next? You can post a comment on this article.

Doc ID 428
Full URL https://imar.spaanjaars.com/428/custom-sorting-with-n-layer-design-classes-and-the-gridview
Short cut https://imar.spaanjaars.com/428/
Written by Imar Spaanjaars
Date Posted 06/13/2007 21:25

Comments

Talk Back! Comment on Imar.Spaanjaars.Com

I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.

When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.

If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the Doc ID of the document.

(Plain text only; no HTML or code that looks like HTML or XML. In other words, don't use < and >. Also no links allowed.