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