65.9K
CodeProject is changing. Read more.
Home

Sorting Generic Collections

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.08/5 (11 votes)

Feb 13, 2007

CPOL

1 min read

viewsIcon

79723

downloadIcon

458

Here is an advanced sortable list that can be used in ASP.Net Pages.

Sample image

Introduction

By default the List<T> class supports the following sort methods Sort(Icomparer<T>) and Sort(Comparison<T>). This does not help us to sort our collections by datatype of the property. This artical help us to fill the above gap.

A User Class

Let us have a simple User class that exposes Id, UserName, JoinDate, UserType and Active Status properties. Let us take the simple List<T> Collection class to hold the list of User objects. The SortableList<T> inherits the List<T> generic class. The Sort method takes to arguments. Let us say propertyName and ascending.

public enum UserTypeEnum
{
    Manager,
    ProjectLead,
    TeamLead,
    SeniorSoftwareEngineer,
    SoftwareEngineer
}
/// <summary />
/// Summary description for User
/// </summary />
public class User
{
    public User(int id, string userName,DateTime joinDate, 
               UserTypeEnum userType, bool isActive)
    {
        this.id = id;
        this.userName = userName;
        this.joinDate = joinDate;
        this.userType = userType;
        this.isActive = isActive;
    }

    private int id;

    public int Id
    {
        get { return id; }
        set { id = value; }
    }
    private string userName = string.Empty ;

    public string UserName
    {
        get { return userName; }
        set { userName = value; }
    }
    private DateTime joinDate = DateTime.MinValue;

    public DateTime JoinDate
    {
        get { return joinDate; }
        set { joinDate = value; }
    }
    private UserTypeEnum userType = UserTypeEnum.SoftwareEngineer;

    public UserTypeEnum UserType
    {
        get { return userType; }
        set { userType = value; }
    }
    private bool isActive = false;

    public bool IsActive
    {
        get { return isActive; }
        set { isActive = value; }
    }
}

Sortable List:

public class SortableList<T>: List<T>
{
    private string _propertyName;
    private bool _ascending;

    public void Sort(string propertyName, bool ascending)
    {
        //Flip the properties if the parameters are the same
        if (_propertyName == propertyName && _ascending == ascending)
            _ascending = !ascending;
        //Else, new properties are set with the new values
        else
        {
            _propertyName = propertyName;
            _ascending = ascending;
        }

        PropertyDescriptorCollection properties
                                = TypeDescriptor.GetProperties(typeof(T));
        PropertyDescriptor propertyDesc = properties.Find(propertyName, true);

        // Apply and set the sort, if items to sort
        PropertyComparer<T> pc = new PropertyComparer<T>(propertyDesc, 
                  (_ascending) ? ListSortDirection.Ascending : 
                   ListSortDirection.Descending);
        this.Sort(pc);
    }
The GetProperties of TypeDescriptor class returns the collection of properties on a component or type and Find method of PropertyDescriptorCollection returns the PropertyDescriptor with the specified name, using a Boolean to indicate whether to ignore case. A PropertyDescriptor with the specified name, or a null reference if the property does not exist.

Now, we can use any property comparer class to compare the values of the property. Here I use PropertyComaparer<T> class that wrote by Rockford Lhotka in MSDN.

PropertyComparer builds on a comparison algorithm based built by Rockford Lhotka and turns it into a generic property comparer for any type. (Note: While a detailed analysis of the comparer is beyond the scope of this article, a brief discussion will suffice, although I urge you to read Rocky's great article and inspect the code sample).

That's it! We are ready to implement this sortable list into our ASP.NET pages.

Code Behind File:

protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            SortableList<user> list = BuildList();
            Cache.Insert("Users", list, null,
                System.Web.Caching.Cache.NoAbsoluteExpiration,
                System.Web.Caching.Cache.NoSlidingExpiration,
                System.Web.Caching.CacheItemPriority.High,
                null);
            UsersGridView.DataSource = list;
            UsersGridView.DataBind();
        }
    }
    protected void UsersGridView_PageIndexChanging(object sender, 
                                                   GridViewPageEventArgs e)
    {
        SortableList<user> list = Cache["Users"] as SortableList<user>;

        UsersGridView.PageIndex = e.NewPageIndex;
        UsersGridView.DataSource = list;
        UsersGridView.DataBind();
    }
    protected void UsersGridView_Sorting(object sender, 
                                         GridViewSortEventArgs e)
    {
        SortableList<user> list = Cache["Users"] as SortableList<user>;

        list.Sort(e.SortExpression, 
                  (e.SortDirection == SortDirection.Ascending));
        //Add the sorted collection back to the cache
        Cache.Insert("Users", list, null,
                System.Web.Caching.Cache.NoAbsoluteExpiration,
                System.Web.Caching.Cache.NoSlidingExpiration,
                System.Web.Caching.CacheItemPriority.High,
                null);
        
        UsersGridView.DataSource = list;
        UsersGridView.DataBind();
    }