Sorting is one of the most common requirements in all grid controls, irrespective of their platforms (ActiveX, WinForms, ASP.NET, WPF, SilverLight). When the grid is bound, sorting is done automatically when user clicks on column header. The reason is the underlying data source handles it. However, in case of an unbound grid, sorting is not possible as there is no datasource to handle this operation. With C1Flexgrid for WPF, we can handle, and implement the sort manually even if its Unbound. Let's see how. We will begin by adding columns to C1FlexGrid and populating data. To do so, you can refer to this documentation link. When C1Flexgrid is loaded, sorting needs to be applied when user clicks on the column header. We can handle this in the Click event of the control as shown in the code :

void \_flex\_Click(object sender, MouseButtonEventArgs e)  
<pre>{  
    var ht = _flex.HitTest(e);  

    // sort column when user clicks a column header  
    if (ht.CellType == CellType.ColumnHeader)  
    {  
        var col = _flex.Columns[ht.Column];  
        var sortDirection = (col.Tag is ListSortDirection) && (ListSortDirection)col.Tag ==  

        ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;  
        col.Tag = sortDirection;  
//implement sort logic on this column  
        SortColumn(col, sortDirection);  
        foreach (C1.WPF.FlexGrid.Column column in _flex.Columns)  
        {  
            if ((column.Index != col.Index))  
            {  
               column.Tag = null;  
            }  
        }  
    }  

    // toggle Boolean cells even when the click is outside the box  
    if (ht.CellType == CellType.Cell)  
    {  
        // check that it is a Boolean cell  
        if (_flex.Columns[ht.Column].DataType == typeof(bool))  
        {  
           // check that it is a single cell (not when extending the selection)  
           if (_flex.Selection.IsSingleCell)  
           {  
                // update Boolean value  
                var value = _flex[ht.Row, ht.Column];  
                _flex[ht.Row, ht.Column] = value is bool && Convert.ToBoolean(value) ? false : true;  

                // we're done with this event  
                e.Handled = true;  
           }  
        }  
     }  

     //design column column header (post-sort)  
     _flex.CellFactory = new SortCellFactory();  
}  

Here's the function definition for SortColumn() method that is used in the click event to implement sort on the column whose Header was clicked.



// sort a column given a sort direction  
private void SortColumn(Column col, ListSortDirection sortDirection)  
{  
     // build row list  
     var list = new List<Row>();  
     foreach (C1.WPF.FlexGrid.Row row in _flex.Rows)  
     {  
           list.Add(row);  
     }  

     // sort row list  
     list.Sort(new RowComparer(col, sortDirection));  

     // re-populate grid with sorted rows  
     _flex.Rows.Clear();  
     foreach (C1.WPF.FlexGrid.Row row in list)  
     {  
         _flex.Rows.Add(row);  
     }  
}  

Above function used the Class RowComparer which implements IComparer interface for sorting. Here's the Class definition.


public class RowComparer : IComparer<Row>  
{  
    private Column _col;  
    private ListSortDirection _sortDirection;  

    public RowComparer(Column col, ListSortDirection sortDirection)  
    {  
        _col = col;  
        _sortDirection = sortDirection;  
    }  

    public int Compare(C1.WPF.FlexGrid.Row x, C1.WPF.FlexGrid.Row y)  
    {  
        var v1 = x[_col];  
        var v2 = y[_col];  

        // compare values  
        int cmp = 0;  
        if (v1 == null && v2 != null)  
        {  
            cmp = -1;  
        }  
        else if (v1 != null && v2 == null)  
        {  
                  cmp = +1;  
                }  
                else if (v1 is IComparable && v2 is IComparable)  
                {  
                   cmp = ((IComparable)v1).CompareTo(v2);  
                }  

                // honor sort direction  
                if (_sortDirection == ListSortDirection.Descending)  
                {  
                    cmp = -cmp;  
                }  

                // return result  
                return cmp;  
     }  
}  

Lastly, when header is clicked and the sort implemented, the header elements comprising TextBlock that contains Header text, sortGlyph/SortIcon/SortIndicator - need to be updated too. This is taken care of by CellFactory (observe last line of code in the Click event where it is called).


public class SortCellFactory : CellFactory  
{  
     public override void CreateColumnHeaderContent(C1FlexGrid grid, Border bdr, CellRange range)  
     {  
         var col = grid.Columns[range.Column];  
         base.CreateColumnHeaderContent(grid, bdr, range);  
         if ((col.Tag != null))  
         {  
             if ((ListSortDirection)col.Tag == ListSortDirection.Descending)  
             {  
                 Grid header = new Grid();  
                 TextBlock tb = new TextBlock();  
                 if (bdr.Child != null)  
                 {  
                    tb = bdr.Child as TextBlock;  
                 }  
                         bdr.Child = null;  
                         tb.HorizontalAlignment = HorizontalAlignment.Left;  
                         tb.VerticalAlignment = VerticalAlignment.Center;  
                         header.Children.Add(tb);  
                         Polygon sort = new Polygon();  
                         sort.Fill = Brushes.Black;  
                         sort.FillRule = FillRule.EvenOdd;  
                         sort.HorizontalAlignment = HorizontalAlignment.Right;  
                         sort.VerticalAlignment = VerticalAlignment.Center;  
                         sort.Points = new PointCollection(new List<Point> {  
                                             new Point(0, 4),  
                                              new Point(8, 4),  
                                              new Point(4, 0)  
                                       });  
                         header.Children.Add(sort);  
                         bdr.Child = header;  
                    }  
                    else if ((ListSortDirection)col.Tag == ListSortDirection.Ascending)  
                    {  
                         Grid header = new Grid();  
                         TextBlock tb = new TextBlock();  
                         if (bdr.Child != null)  
                         {  
                            tb = bdr.Child as TextBlock;  
                         }  
                         tb.HorizontalAlignment = HorizontalAlignment.Left;  
                         tb.VerticalAlignment = VerticalAlignment.Center;  
                         bdr.Child = null;  
                         header.Children.Add(tb);  
                         Polygon sort = new Polygon();  
                         sort.HorizontalAlignment = HorizontalAlignment.Right;  
                         sort.VerticalAlignment = VerticalAlignment.Center;  
                         sort.Fill = Brushes.Black;  
                         sort.FillRule = FillRule.EvenOdd;  
                         sort.Points = new PointCollection(new List<Point> {  
                                             new Point(0, 0),  
                                             new Point(8, 0),  
                                             new Point(4, 4)  
                                      });  
                         header.Children.Add(sort);  
                         bdr.Child = header;  
                     }  
             }  
      }  
}  

And, we have fully functional and sort capable, unbound C1Flexgrid. Download the samples for complete implementation. Download CS Sample Download VB Sample