Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C#

DataGrid with Customizable Column Sorting

Rate me:
Please Sign up or sign in to vote.
4.58/5 (13 votes)
4 Sep 2006CPOL3 min read 61.3K   1.1K   27   2
Reusable extension of the DataGrid control that allows the customization of the sorting event for each column of the grid.
Sample Image - ccsdatagrid.jpg

Contents

Introduction

While working on a project, I was required to change the default behavior of a DataGrid: when clicking one precise column, I needed to sort the contents of the grid not by the column the user was clicking, but by another two columns in the grid. Searching the web, I found that several people has a need more or less similar to mine (sorting the grid by all columns except one, sorting the grid remembering the last column the grid was sorted by and combining the sorting with the new column selected, etc.).

So I decided to extend the DataGrid so that the developer could define specific sorting events that will be raised when the column they have chosen has been clicked. This way we can ignore one column and not sort it or make a complex sorting using several columns or... whatever we need (I hope :D).

Background

The basics of working with DataGrid, I suppose.

Using the Code

Using the control is quite easy, first add the CSSDataGrid (which is, in fact, the control that extends the DataGrid) to the form that is being developed and then follow these two steps:

  • Call the AddNewCustomizedSortingEvent to add a new specific sort event for the table and the column we like to the CSSDataGrid in the form that's being created:
    C#
    this.ccsDataGrid1.AddNewCustomizedSortingEvent("ParentTable","ParentItem",
    new SortDataGridColumnEventHandler(this.OrderParentItemColumn));
  • Implement the sorting event. Here two examples are presented, the first one showing how to ignore the sorting for the column (quite easy), and the second one showing how to sort the grid using two columns, instead of the one clicked:
    C#
    private void OrderParentItemColumn(object sender, 
    SortDataGridColumnEventArgs e)
    {
    }  
    C#
    private void OrderChildItemColumn(object sender, 
                SortDataGridColumnEventArgs e)
    {
        if (e.DataViewToSort.Sort == "ParentItem, childID DESC")
            e.DataViewToSort.Sort = "ParentItem DESC, childID DESC";
        else
            e.DataViewToSort.Sort = "ParentItem, childID DESC";
    }  

As you may see, this way we have access to the view that is currently shown in the grid, so we can also filter the view or many other things that are not in the scope of the article.

We may also clear programmatically the sort events of the CSSDataGrid:

C#
this.ccsDataGrid1.ClearAllCustomizedSortEvents();

How It Works?

Classes to Manage Sort Events

First of all, SortDataGridColumnEventArgs are created to be passed to a sort event declared as a delegate, SortDataGridColumnEventHandler. The SortDataGridColumnEventArgs has as fields the name and index of the column that has been clicked and the current DataView that is being shown in the DataGrid.

C#
public class SortDataGridColumnEventArgs : EventArgs
{
    #region Fields
    private int _columnIndex;
    private string _columnName;
    private DataView _viewToSort;
    #endregion
       
    ...
}

The rest of the class contains a constructor to assign the fields and properties to access them.

Extension of the DataGrid

Now it's time to extend the DataGrid and implement the CCSDataGrid. I will store the SortDataGridColumnEventHandler indexed by the column in Hashtable that is stored in another Hashtable indexed by the table name. The root Hashtable is the only field needed in the CCSDataGrid control.

C#
/// Hashtable to store hashtables, one per each table in the dataset, and each one of
/// them containing column names and its respective customized sorting events
private Hashtable _hashColumnSortingEvents;

We have a couple of properties to access the CurrentView in the DataGrid, and the CurrentTableSortColumnEvents. Also there are several methods to add events to columns and to clear them:

C#
#region Properties

/// Return the CurrentTable Hashtable with the sort column events
protected Hashtable CurrentTableSortColumnEvents
{
    get 
    { 
        if (this.CurrentView == null)
            return null;
        else if (_hashColumnSortingEvents[this.CurrentView.Table.TableName] == null)
            return null;
        else
            return (Hashtable) 
                _hashColumnSortingEvents[this.CurrentView.Table.TableName]; 
    }
}

/// Gets the currently visible DataView
/// Returns null when no DataView is set.
public DataView CurrentView 
{
    get 
    {
        if (base.ListManager == null)
            return null;
        else
            return base.ListManager.List as DataView; 
    }
}
    
#endregion

/******************
 * PUBLIC METHODS *
 ******************/
 
#region Public method to add the sorting delegate method to the column

/// Add a Customized Sort Event to the column passed in the table passed too
public bool AddNewCustomizedSortingEvent(string tableName, int column, 
    SortDataGridColumnEventHandler theEvent)
{
    try
    {
        if (this.CurrentView != null)
        {
            if ((column < this.CurrentView.Table.Columns.Count) &&
                (column > 0))
            {
                AddNewCustomizedSortingEvent(tableName,
                    this.CurrentView.Table.Columns[column].ColumnName,
                    theEvent);
                return true;
            }
        }
        
        return false;
    }
    catch
    {
        return false;
    }
}

/// Add a Customized Sort Event to the column passed in the table passed too
public void AddNewCustomizedSortingEvent(string tableName, string columnName, 
    SortDataGridColumnEventHandler theEvent)
{
    if (this._hashColumnSortingEvents[tableName] == null)
        this._hashColumnSortingEvents[tableName] = new Hashtable();
        
    ((Hashtable) this._hashColumnSortingEvents[tableName])[columnName] = theEvent;
}

#endregion

#region Clear the sort events
    
/// Clear all the customized sort events
public void ClearAllCustomizedSortEvents()
{
    this._hashColumnSortingEvents.Clear();
}

/// Clear the customized sort events for the table passed
public void ClearCustomizedSortEventsForTable(string tableName)
{
    if (this._hashColumnSortingEvents[tableName] != null)
        ((Hashtable) this._hashColumnSortingEvents[tableName]).Clear();
}

#endregion

The trick in the control is in the OnMouseDown event handler, where we'll check if a column header has been clicked and if it had a SortDataGridColumnEventHandler assigned. If so, that handler is called:

C#
protected override void OnMouseDown(MouseEventArgs e)
{
    Point pt = new Point(e.X, e.Y);
    DataGrid.HitTestInfo hti = this.HitTest(pt);
    
    // If the selected column is one with a customized sorting event then
    // the event is called, otherwise continue with the OnMouseDown event
    
    // Get the sort event if it exists...
    SortDataGridColumnEventHandler sortEvent = null;
    if ( (hti.Column > 0) && (this.CurrentTableSortColumnEvents != null) )
    {
        sortEvent = (SortDataGridColumnEventHandler)
            this.CurrentTableSortColumnEvents[
                this.CurrentView.Table.Columns[hti.Column].ColumnName];
    }
    
    // Then if exists the event is called
    if( (hti.Type == HitTestType.ColumnHeader) && 
        (sortEvent != null) &&
        (this.CurrentView != null) )
    {
        // Call the customized sorting event
        SortDataGridColumnEventArgs sortEventArgs = 
	   new SortDataGridColumnEventArgs(hti.Column,
            this.CurrentView.Table.Columns[hti.Column].ColumnName,this.CurrentView);
        sortEvent(this,sortEventArgs);
    }
    else
    {
        base.OnMouseDown(e);
    }
}

Points of Interest

In the code that's attached to the article, the CCSDataGrid does not extend the DataGrid but an LCGBaseDataGrid, that is a base class where I'll put all the basic methods, fields and properties that I want to be inherited by all the extensions that I may do. In fact, the property CurrentView is declared there.

History

  • September 2006: First release, my very first article on CodeProject

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Spain Spain
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralSort Multiple Column Pin
muh_ghalib12-Sep-06 1:56
muh_ghalib12-Sep-06 1:56 
GeneralRe: Sort Multiple Column Pin
Luis Carlos Gallego12-Sep-06 4:17
Luis Carlos Gallego12-Sep-06 4:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.