This post will show you how to override the built-in sorting functionality and sort the DataGrid data using the SortDescription class. The data content is sorted when a user clicks a column header.
1. The following example defines a DataGrid with six columns that bind to the Name, Date, Product, Quantity, UnitPrice and SalesAmount properties of the EmployeeSaleRecord class.
<viblendDataGrid:DataGrid AutoGenerateColumns="True" Height="200" VerticalAlignment="Center" Name="dataGrid" Width="350">
<viblendDataGrid:DataGrid.BoundFields>
<viblendDataGrid:BoundField Text="Name" DataField="Name" Width="160" CellStyle="{StaticResource textCentered}"/>
<viblendDataGrid:BoundField Text="Date" DataField="Date" Width="140" />
<viblendDataGrid:BoundField Text="Product" DataField="Product" Width="140" CellStyle="{StaticResource textCentered}"/>
<viblendDataGrid:BoundField Text="Quantity" DataField="Quantity" Width="90" CellStyle="{StaticResource textCentered}"/>
<viblendDataGrid:BoundField Text="Unit Price" DataField="UnitPrice" Width="74"/>
<viblendDataGrid:BoundField Text="Sales Amount" DataField="SalesAmount" Width="88"/>
</viblendDataGrid:DataGrid.BoundFields>
</viblendDataGrid:DataGrid>
2. Create column header templates with up and down arrow elements that will be displayed when the grid data is sorted.
<UserControl.Resources>
<Style x:Name="textCentered" TargetType="viblendDataGrid:GridCellElement">
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>
<DataTemplate x:Key="SortAscendingTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding}"></TextBlock>
<Path Grid.Column="1" x:Name="sortAscElement" Height="5" Width="9" Stretch="Fill" Stroke="#FFFFFFFF" Data="M4.5,5 L0,0 L9,0 z" RenderTransformOrigin="0.0,0.0">
<Path.Fill>
<LinearGradientBrush EndPoint="-0.237,0.525" StartPoint="0.679,0.525">
<GradientStop Color="#55FFFFFF"/>
<GradientStop Color="#55FFFFFF" Offset="0.991"/>
</LinearGradientBrush>
</Path.Fill>
</Path>
</Grid>
</DataTemplate>
<DataTemplate x:Key="SortDescendingTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding}"></TextBlock>
<Path Grid.Column="1" x:Name="sortDescElement" Height="5" Width="9" Stretch="Fill" Stroke="#FFFFFFFF" Data="M4.5,0 L9,5 L0,5 z" RenderTransformOrigin="0.0,0.0" >
<Path.Fill>
<LinearGradientBrush EndPoint="-0.237,0.525" StartPoint="0.679,0.525">
<GradientStop Color="#55FFFFFF"/>
<GradientStop Color="#55FFFFFF" Offset="0.991"/>
</LinearGradientBrush>
</Path.Fill>
</Path>
</Grid>
</DataTemplate>
</UserControl.Resources>
3. Create CollectionViewSource, HierarchyItem and bool? fields in the code behind.
4. Bind the DataGrid to a List of EmployeeSaleRecord objects. Set the selection mode to row selection and hide the row headers.
C#
// Bind DataGrid
dataGrid.ItemsSource = listSaleRecord;
dataGrid.SelectionMode = DataGrid.SELECTION_MODE.FULL_ROW_SELECT;
dataGrid.RowsHierarchy.Visible = false;
VB .NET
' Bind DataGrid
dataGrid.ItemsSource = listSaleRecord
dataGrid.SelectionMode = DataGrid.SELECTION_MODE.FULL_ROW_SELECT
dataGrid.RowsHierarchy.Visible = False
5. To sort the data according to the contents of a column, the example defines an event handler to handle the HierarchyItemMouseClick event that occurs when you press the column header. In the event handler, toggle the sorting order and set the DataTemplate property of the HierarchyItem object depending on the sort order. Call the Sort method and set the DataGrid.ItemsSource property to point to the view. Doing this, the DataGrid will be refreshed and sorted.
C#
// Subscribe to HierarchyItemMouseClick event.
dataGrid.HierarchyItemMouseClick += new DataGrid.HierarchyItemMouseButtonEventHandler(dataGrid_HierarchyItemMouseClick);
void dataGrid_HierarchyItemMouseClick(object sender, HierarchyItemMouseButtonEventArgs args)
{
if (clickedItem != null && !args.HierarchyItem.BoundField.DataField.Equals(clickedItem.BoundField.DataField))
{
clickedItem.BoundField.DataTemplate = null;
ascending = null;
}
clickedItem = args.HierarchyItem;
clickedItem.BoundField.DataContext = clickedItem.BoundField.DataField;
// Load the column's DataTemplate
if (ascending == null)
{
ascending = true;
clickedItem.BoundField.DataTemplate = this.Resources["SortDescendingTemplate"] as DataTemplate;
}
else if (ascending.HasValue && !ascending.Value)
{
ascending = null;
clickedItem.BoundField.DataTemplate = null;
}
else if (ascending.HasValue && ascending.Value)
{
ascending = false;
clickedItem.BoundField.DataTemplate = this.Resources["SortAscendingTemplate"] as DataTemplate;
}
if (ascending == null)
{
dataGrid.ItemsSource = listSaleRecord;
}
else
{
SortDescription sortDescription = new SortDescription(args.HierarchyItem.BoundField.DataField, ascending == true ? ListSortDirection.Ascending : ListSortDirection.Descending);
ICollectionView view = Sort(sortDescription, args.HierarchyItem.BoundField.DataField, this.listSaleRecord);
dataGrid.ItemsSource = view;
}
}
VB .NET
' Subscribe to HierarchyItemMouseClick event.
Private dataGrid.HierarchyItemMouseClick += New DataGrid.HierarchyItemMouseButtonEventHandler(AddressOf dataGrid_HierarchyItemMouseClick)
Private Sub dataGrid_HierarchyItemMouseClick(ByVal sender As Object, ByVal args As HierarchyItemMouseButtonEventArgs)
If clickedItem IsNot Nothing AndAlso (Not args.HierarchyItem.BoundField.DataField.Equals(clickedItem.BoundField.DataField)) Then
clickedItem.BoundField.DataTemplate = Nothing
ascending = Nothing
End If
clickedItem = args.HierarchyItem
clickedItem.BoundField.DataContext = clickedItem.BoundField.DataField
' Load the column's DataTemplate
If ascending Is Nothing Then
ascending = True
clickedItem.BoundField.DataTemplate = TryCast(Me.Resources("SortDescendingTemplate"), DataTemplate)
ElseIf ascending.HasValue AndAlso (Not ascending.Value) Then
ascending = Nothing
clickedItem.BoundField.DataTemplate = Nothing
ElseIf ascending.HasValue AndAlso ascending.Value Then
ascending = False
clickedItem.BoundField.DataTemplate = TryCast(Me.Resources("SortAscendingTemplate"), DataTemplate)
End If
If ascending Is Nothing Then
dataGrid.ItemsSource = listSaleRecord
Else
Dim sortDescription As New SortDescription(args.HierarchyItem.BoundField.DataField,If(ascending = True, ListSortDirection.Ascending, ListSortDirection.Descending))
Dim view As ICollectionView = Sort(sortDescription, args.HierarchyItem.BoundField.DataField, Me.listSaleRecord)
dataGrid.ItemsSource = view
End If
End Sub
6. Implement the Sort method. Add the SortDescription instance to the CollectionViewSource and return the view which will be used as DataGrid items source.
C#
public virtual ICollectionView Sort(SortDescription sortDescription, string columnName, System.Collections.IEnumerable itemsSource)
{
if (sortDescription == null)
return null;
string displayMember = columnName;
if (String.IsNullOrEmpty(displayMember))
{
displayMember = "";
}
viewSource.SortDescriptions.Clear();
if (itemsSource != null)
{
if (itemsSource as ICollectionView != null)
{
viewSource.Source = (itemsSource as ICollectionView).SourceCollection;
}
else
{
viewSource.Source = itemsSource;
}
viewSource.SortDescriptions.Add(sortDescription);
return viewSource.View;
}
return null;
}
VB .NET
Public Overridable Function Sort(ByVal sortDescription As SortDescription, ByVal columnName As String, ByVal itemsSource As System.Collections.IEnumerable) As ICollectionView
If sortDescription Is Nothing Then
Return Nothing
End If
Dim displayMember As String = columnName
If String.IsNullOrEmpty(displayMember) Then
displayMember = ""
End If
viewSource.SortDescriptions.Clear()
If itemsSource IsNot Nothing Then
If TryCast(itemsSource, ICollectionView) IsNot Nothing Then
viewSource.Source = (TryCast(itemsSource, ICollectionView)).SourceCollection
Else
viewSource.Source = itemsSource
End If
viewSource.SortDescriptions.Add(sortDescription)
Return viewSource.View
End If
Return Nothing
End Function
Download demo project: DataGridCustomSortingDemo.zip