Sorting GridView Using IComparer
By AzamSharp
Views: 10892

Introduction:

Sorting in a GridView is a common scenario required by most of the web applications. In my previous articles I discussed GridView Sorting Using Bound Columns and Sorting GridView with Autogenerated Columns. In both of my previous articles I used the help of DataView object to sort the container. Most of the enterprise applications take advantage of the entity classes which allow the basis for object oriented programming. In this article I will explain how you can sort the GridView control which uses a generic list as its data source.

Creating a GridView Control

Let's first create a GridView control. The GridView will contain two bound columns and two template columns. Take a look at the code below: 

 <asp:GridView EnableSortingAndPagingCallbacks="false" AllowSorting="true" ID="gvUsers"
runat="server" AutoGenerateColumns="false" OnSorting="gvUsers_Sorting" > <Columns>
<asp:BoundField DataField="FirstName" HeaderText="First Name" SortExpression="FirstName"
/> <asp:BoundField DataField = "LastName" HeaderText= "Last Name" SortExpression="LastName"
/> <asp:TemplateField HeaderText="Class Code" SortExpression="ClassCode">
<ItemTemplate> <asp:Label ID="lblClassCode" runat="server" Text='<%#
Eval("ClassCode") %>' /> </ItemTemplate> </asp:TemplateField>
</Columns> </asp:GridView>
Notice that I have also included the SortExpression for all the columns of the GridView control. The SortExpression denotes the field which is used for sorting the GridView.

Creating an Entity Class

I will create a very simple User entity class. Once, the class is created I will fill the generic List with the objects and send it back to the client where they are displayed in the GridView.

Take a look at the code below which creates a very simple entity class User.cs:

 public class User
{
private string firstName;
private string lastName;
private string classCode;

public string FirstName
{
get { return this.firstName; }
set { this.firstName = value; }
}

public string LastName
{
get { return this.lastName; }
set { this.lastName = value; }
}

public string ClassCode
{
get { return this.classCode; }
set { this.classCode = value; }
}

public User()
{

}
}


Implementing GetAllUsers Method

The GetAllUsers method is responsible for fetching the list of users and sending the list back to the client. In the code below I am using a generic list which can contain objects of type User.
public List GetAllUsers()
{
List users = new List();

string connectionString = @"Server=localhost;Database=School;Trusted_Connection=true";
SqlConnection myConnection = new SqlConnection(connectionString);

SqlCommand myCommand = new SqlCommand("SELECT * FROM Users", myConnection);


myConnection.Open();
SqlDataReader reader = myCommand.ExecuteReader();
while (reader.Read())
{
User user = new User();
user.FirstName = reader["FirstName"] as String;
user.LastName = reader["LastName"] as String;
user.ClassCode = reader["ClassCode"] as String;

users.Add(user);
}

myConnection.Close();
myCommand.Dispose();

return users;

}


Binding Data Source to GridView Control

Now, that we have filled the list with User objects we can bind the list to the GridView. Take a look at the code below which binds the list of users to the GridView control.

 private void BindData()
{
User user = new User();
gvUsers.DataSource = user.GetAllUsers();
gvUsers.DataBind();


}
 

Although you have bind the list to the GridView, the sorting mechanism is not yet enabled. In order to deal with sorting which is dependent on the list of objects you will need to create a Comparer which implements the IComparer interface. The IComparer interface contains a method name CompareTo, which you can implement to compare the objects.

Implementing the IComparer Interface

We will create a class called GenericComparer which will implement the IComparer interface. The GenericComparer class contains bunch of stuff so let's check it out in detail.

SortDirection : The sort direction indicates the direction of the sort. This can be ascending or descending.

 public SortDirection SortDirection
{
get { return this.sortDirection; }
set { this.sortDirection = value; }
}

 

GenericComparer Constructor : The contructor takes two arguments namely, sortExpression and sortDirection. The sortExpression is the name of the GridView column to sort and sortDirection denotes the direction in which the column has to be sorted. The sortDirection can be ascending or descending.

 public GenericComparer(string sortExpression, SortDirection sortDirection)
{
this.sortExpression = sortExpression;
this.sortDirection = sortDirection;
}


CompareTo Method: The CompareTo method is the place where all the fun happens. The CompareTo method takes a generic T as an argument which means it can accept any type of object. Then it uses the sortExpression to extract the property out of the type and finally it performs the comparison on the properties.

public int Compare(T x, T y)
{
PropertyInfo propertyInfo = typeof(T).GetProperty(sortExpression);
IComparable obj1 = (IComparable)propertyInfo.GetValue(x, null);
IComparable obj2 = (IComparable)propertyInfo.GetValue(y, null);


if (SortDirection == SortDirection.Ascending)
{
return obj1.CompareTo(obj2);
}
else return obj2.CompareTo(obj1);

}

 

Using the Code

An ideal place to call the sorting method is inside the GridView_Sorting event which is fired when you clicked the column header of the GridView control. Take a look at the code below:

 protected void gvUsers_Sorting(object sender, GridViewSortEventArgs e)
{
User user = new User();
List users = user.GetAllUsers();


users.Sort(new GenericComparer(e.SortExpression, GridViewSortDirection));

gvUsers.DataSource = users;
gvUsers.DataBind();
}

 

Now, if you click on the GridView header it will be sorted based on what column you clicked on.

I hope you liked the article, happy coding!

By AzamSharp


Enter Comment/Feedback
  •  
  •  
  •  
  •  
  •  

Comments/Feedbacks
Subject: Many Thanks
Name: Steck
Date: 2/15/2007 8:12:29 AM
Comment:
Fantastic !!!
Thanks to you, i how you a lot of developpement time !
Subject: Awesome Work
Name: Rodney
Date: 2/22/2007 1:25:00 PM
Comment:
I did have one question. How do you deal with items that are null? When I apply this technique to my data, I get errors on columns that have null values. Column that have values (string, int, etc) for every record sort just fine.
Subject: Use DBNull.Value
Name: AzamSharp
Date: 2/22/2007 6:43:26 PM
Comment:
You can use DBNull.Value to check against NULL values.
Subject: Thanks for this wonderful artcile.
Name: Gaurav Rawat
Date: 4/23/2007 3:43:47 AM
Comment:
Hi Azam,
Thanks for this wonderful article.
Subject: gridview
Name: ravi
Date: 6/27/2007 2:57:45 AM
Comment:
great
Subject: Good
Name: harish
Date: 6/29/2007 12:21:13 PM
Comment:
Nice. Thank you.
Subject: Great!
Name: Ahmad Abu-Raddad
Date: 7/19/2007 2:15:23 AM
Comment:
Awesome, thank you very much.

I was doing the same sort mechanism but was wondering how to do a generic class that works for any business entity.

Cheers
Subject: Sorting in opposite direction
Name: San,
Date: 9/27/2007 5:03:45 PM
Comment:
Great!! Good article,

Is there any generic way way to do 2 direction (asc/desc) sorting?

Regards
Subject: convert to VB.NET
Name: Tolga
Date: 12/17/2007 2:59:00 AM
Comment:
Great Job.

But I have a problem if I use this code with vb.net. I got the following error:

Error 1 Class 'GenericComparer' must implement 'Function Compare(x As T, y As T) As Integer' for interface 'System.Collections.Generic.IComparer(Of T)'.


the vb.net code like this:

Imports System
Imports System.Data
Imports System.Configuration
Imports System.Web
Imports System.Web.Security
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts
Imports System.Web.UI.HtmlControls
Imports System.Collections
Imports System.Collections.Generic
Imports System.Reflection

Public Class GenericComparer(Of T)
Implements IComparer(Of T)

Private m_sortDirection As SortDirection
Private sortExpression As String

Public Property SortDirection() As SortDirection
Get
Return Me.m_sortDirection
End Get
Set(ByVal value As SortDirection)
Me.m_sortDirection = value
End Set
End Property

Public Sub New(ByVal sortExpression As String, ByVal sortDirection As SortDirection)
Me.sortExpression = sortExpression
Me.m_sortDirection = sortDirection
End Sub

Public Function Compare(ByVal x As T, ByVal y As T) As Integer
Dim propertyInfo As PropertyInfo = GetType(T).GetProperty(sortExpression)
Dim obj1 As IComparable = DirectCast(propertyInfo.GetValue(x, Nothing), IComparable)
Dim obj2 As IComparable = DirectCast(propertyInfo.GetValue(y, Nothing), IComparable)

If SortDirection = SortDirection.Ascending Then
Return obj1.CompareTo(obj2)
Else
Return obj2.CompareTo(obj1)
End If
End Function
End Class
Subject: My Hero.
Name: Al.
Date: 1/29/2008 6:46:16 AM
Comment:
Thanks Dude, You saved the day!
Subject: re: convert to VB.NET
Name: Michael
Date: 2/12/2008 1:08:12 PM
Comment:
Tolga,

Public Function Compare(ByVal x As T, ByVal y As T) As Integer Implements IComparer(Of T).Compare

Fixed the problem for me.
Subject: Superb Article
Name: siva
Date: 3/8/2008 5:43:48 AM
Comment:
Wow article
Subject: source incomplete
Name: Allan Mikaya
Date: 3/8/2008 5:04:09 PM
Comment:
I didnt see "BasePage" in the source.
Subject: RE: Source Incomplete
Name: AzamSharp
Date: 3/8/2008 8:12:50 PM
Comment:
Hi, Hmmm thats strange! You can add a cs file and inherit from System.Web.UI.Page and name it the BasePage.cs. Now, all your pages will inherit from this BasePage instead of the System.Web.UI.Page.
Subject: sorting problem with referenced objedts
Name: kirsh
Date: 4/3/2008 12:08:01 AM
Comment:
Hi thanks 4 ur nice article... but the problem is that when iam genrating list lst hav hospital list ,, that references patients...
While sorting
case 1:hospital.hospital id-- working fine
case 2: hospital.patiend.patienid-- not working ...

can u plzz help me to solve tis problemmmmm

Thanks..
Subject: problem with referedclasses
Name: raj
Date: 4/4/2008 4:33:17 AM
Comment:
refernces problem
Like:MASTER AND STUDENT Classess
InCase:MASTER.masterID--Working fine

InCase:MASTER.STUDENT.studentID--Problem
ERROR:Object Refence is not set to an instance of object

Waitng for ur replyy..
Thnks.
Subject: Thanks i got solution
Name: raj
Date: 4/8/2008 12:17:52 AM
Comment:
Hi i got solution

thanku..........
Subject: Simply... Great solution
Name: Luis Canales
Date: 4/27/2008 7:14:21 PM
Comment:
I searching for something like this for my enterprise aaplication... and you give the light... thanx..
Subject: Getting it to work with ObjectDataSource?
Name: David C
Date: 4/29/2008 11:56:39 AM
Comment:
Is it possible to get it to work with ObjectDataSource? I get the "The data source 'odsFacilities' does not support sorting with IEnumerable data. Automatic sorting is only supported with DataView, DataTable, and DataSet" error
Subject: Getting it to work with ObjectDataSource?
Name: David C
Date: 4/29/2008 11:58:37 AM
Comment:

Thank you for the wonderful article, but I can't get the code to work, and it is probably because I am new to Generics.

I am seeing that you are skipping the type argument for T (in this case User).
Subject: Sorting null
Name: Peter
Date: 5/22/2008 8:26:52 PM
Comment:
Hi Thanks for this solution.
I also had the Null problem mentioned in an earlier comment. I added the following lines in the generic compare to get is working:
if (SortDirection == SortDirection.Ascending)
{
if (obj1 == null)
return (obj2 == null) ? 0 : -1;
return obj1.CompareTo(obj2);
}
if (obj2 == null)
return (obj1 == null) ? 0 : -1;
return obj2.CompareTo(obj1);

cheers
Subject: Descending Sort
Name: Andrew
Date: 6/5/2008 5:36:33 AM
Comment:
Nice article. It seems that without an ObjectDataSource, the SortExpression and SortDirection properties on the GridView control are not set. As a result, the sorts are always ascending. Do you know of a solution to this problem?

Cheers,
Andrew
Subject: re: Descending Sort
Name: AzamSharp
Date: 6/8/2008 8:16:41 AM
Comment:
Hi Andrew,

Not sure if I understand your question. But the SortExpression and the SortDirection are the GridView properties and they have no dependency on the ObjectDataSource control.



Join WebHost4Life.com






Copyright GridViewGuy 2007-2008