Sorting GridView using IComparer and Reflection

Recently I just did a small job for a client online using IComparer interface to perform sorting on a GridView control.

First I need to create class called Person. This class is going to contain the following properties: FirstName, LastName, Age.

public class Person
{
    private string _firstName;
    private string _lastName;
    private int _age;

    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value; }
    }

    public string LastName
    {
       get { return _lastName; }
       set { _lastName = value; }
    }

    public int Age
    {
       get { return _age; }
       set { _age = value; }
    }
}

Now I need to create a class called PersonComparer that will inherit from the IComparer interface. This comparer class will be use with the Sort() method from a List collection.

 using System.Collections;
 using System.Collections.Generic;
 using System.Reflection;
 using System;

 public class PersonComparer:IComparer
 {
     private string _sortBy;

     public string SortBy
     {
         get { return _sortBy; }
         set { _sortBy = value; }
     }

     public int Compare(Person x, Person y)
     {
         int result = 0;
         string propName = string.Empty;
         string sortDirection = "ASC";

         if (_sortBy.Contains(" DESC"))
         {
             propName = _sortBy.Replace(" DESC", string.Empty).Trim();
             sortDirection = "DESC";
         }

         if (_sortBy.Contains(" ASC"))
         {
             propName = _sortBy.Replace(" ASC", string.Empty).Trim();
             sortDirection = "ASC";
         }

         // Get type of Person Object
         Type t = typeof(Person);

         // Find the property name from the sortExpress passed in SortBy property.
         PropertyInfo propInfo = t.GetProperty(propName);

         if (propInfo != null)
         {
             // Perform comparison on property value.
             result = Comparer.DefaultInvariant.Compare(propInfo.GetValue(x, null), propInfo.GetValue(y, null));

             if (sortDirection.Equals("DESC"))
             {
                 result = -result;
             }
         }
         return result;
     }
 }

Now create a new web page with a GridView control on it. Add the following column details: First Name, Last Name and Age.

image

For each of these column edit the following BoundField properties: HeaderText – First Name, Last Name and Age. SortExpression – FirstName, LastName, Age. DataField – FirstName, LastName, Age.

Make sure that the SortExpression and DataField properties are spelt the same as your Person class property names.

image

Now back to the GridView control properties and find AutoGenerateColumns and set it to False, because I want to define the columns myself. Find AllowSorting and set it to True.

image

Now I we will write some code behind of our aspx page.

  protected void Page_Load(object sender, EventArgs e)
  {
      if (!IsPostBack)
      {
          GridView1.DataSource = GetPeople();
          GridView1.DataBind();
      }
  }

During the Page_Load() method I need to test that the page was not a post back to the server and then I set the GridView DataSource control from a private method called GetPeople() which returns a list of Person object in a List collection. Then I bind the list of Person objects to the GridView control by calling DataBind().

  private List GetPeople()
  {
      List peopleList = new List();
 
      Person person1 = new Person();
      person1.FirstName = "Joe";
      person1.LastName = "Bloggs";
      person1.Age = 34;
      peopleList.Add(person1);
 
      Person person2 = new Person();
      person2.FirstName = "David";
      person2.LastName = "Copperfield";
      person2.Age = 50;
      peopleList.Add(person2);
 
      return peopleList;
  }

Here is my GetPeople() method as you can see it’s declared as private and it returns a List of Person objects. Here we hard code two person who is named Joe Bloggs and David Copperfield, I then add both of them to a list and return it to the calling code.

  protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
  {
      List personList = GetPeople();
      PersonComparer comparer = new PersonComparer();
      if (ViewState["SortExp"] != null && ViewState["SortDir"] != null)
      {
          if (ViewState["SortExp"].ToString() == e.SortExpression)
          {
              if (ViewState["SortDir"].ToString() == "Descending")
              {
                  e.SortDirection = SortDirection.Ascending;
              }
              else
              {
                  e.SortDirection = SortDirection.Descending;
              }
          }
      }
 
      ViewState["SortDir"] = e.SortDirection;
      ViewState["SortExp"] = e.SortExpression;
 
      comparer.SortBy = string.Format("{0} {1}", e.SortExpression, e.SortDirection);
      personList.Sort(comparer);
 
      GridView1.DataSource = personList;
      GridView1.DataBind();
  }

Above I have a sorting event which will be called each time a user clicks on the column header name to sort.

I have a some ViewState variables here to persist some values when a post back occurs. I have used it to store the e.SortExpession and e.SortDirection value from the GridViewSortEventArgs.

On line 23 the value is created for the SortBy property of the PersonComparer object. I am creating a string which contains the sort expression and direction. On line 24 I then pass the PersonComparer object to the Sort() method from the List.

To display the sorted Person on the GridView I reassign the List to the DataSource of the GridView control and then call the DataBind() method.

Well I hope this demonstration is informative to you, and I have the project in a zip file for people to download below.

GridViewSortingReflection.zip

Leave a Reply

Your email address will not be published. Required fields are marked *

Before you post, please prove you are sentient.

What color is the sky on a sunny day?