I have a WPF DataGrid bound to a CollectionViewSource that encapsulates an ObservableCollection. This CollectionViewSource has two main objectives:
1) To group each
I did this by overriding the OnSorting event and implementing it myself.
http://msdn.microsoft.com/en-us/library/system.windows.controls.datagrid.onsorting.aspx
Which basically meant re sorting the ListCollectionView.
Sorry its not too in depth an answer.
DataGrid CustomSorting
<DataGrid attached:DataGridHelpers.UseCustomSort="True" ItemsSource="{Binding Items}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn attached:DataGridHelpers.CustomSorterType="{x:Type comparers:StrLogicalComparer}" Binding="{Binding CodeText}" Header="Code" />
<DataGridTextColumn Header="Number" Binding="{Binding Number}" />
</DataGrid.Columns>
</DataGrid>
Supports nested properties
This answer is very similar to trilson86's solution -- it was based on it -- but it accounts for SortMemberPath
in a manner such that the values passed to your comparer are the actual values of the column, rather than the rows. This facilitates far greater re-use on your sorters. Furthermore, it eliminates the need for a custom sort interface altogether.
DataGridSortBehavior.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace YourNamespace
{
public class DataGridSortBehavior
{
public static IComparer GetSorter(DataGridColumn column)
{
return (IComparer)column.GetValue(SorterProperty);
}
public static void SetSorter(DataGridColumn column, IComparer value)
{
column.SetValue(SorterProperty, value);
}
public static bool GetAllowCustomSort(DataGrid grid)
{
return (bool)grid.GetValue(AllowCustomSortProperty);
}
public static void SetAllowCustomSort(DataGrid grid, bool value)
{
grid.SetValue(AllowCustomSortProperty, value);
}
public static readonly DependencyProperty SorterProperty = DependencyProperty.RegisterAttached("Sorter", typeof(IComparer),
typeof(DataGridSortBehavior));
public static readonly DependencyProperty AllowCustomSortProperty = DependencyProperty.RegisterAttached("AllowCustomSort", typeof(bool),
typeof(DataGridSortBehavior), new UIPropertyMetadata(false, OnAllowCustomSortChanged));
private static void OnAllowCustomSortChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var grid = (DataGrid)obj;
bool oldAllow = (bool)e.OldValue;
bool newAllow = (bool)e.NewValue;
if (!oldAllow && newAllow)
{
grid.Sorting += HandleCustomSorting;
}
else
{
grid.Sorting -= HandleCustomSorting;
}
}
public static bool ApplySort(DataGrid grid, DataGridColumn column)
{
IComparer sorter = GetSorter(column);
if (sorter == null)
{
return false;
}
var listCollectionView = CollectionViewSource.GetDefaultView(grid.ItemsSource) as ListCollectionView;
if (listCollectionView == null)
{
throw new Exception("The ICollectionView associated with the DataGrid must be of type, ListCollectionView");
}
listCollectionView.CustomSort = new DataGridSortComparer(sorter, column.SortDirection ?? ListSortDirection.Ascending, column.SortMemberPath);
return true;
}
private static void HandleCustomSorting(object sender, DataGridSortingEventArgs e)
{
IComparer sorter = GetSorter(e.Column);
if (sorter == null)
{
return;
}
var grid = (DataGrid)sender;
e.Column.SortDirection = e.Column.SortDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;
if (ApplySort(grid, e.Column))
{
e.Handled = true;
}
}
private class DataGridSortComparer : IComparer
{
private IComparer comparer;
private ListSortDirection sortDirection;
private string propertyName;
private PropertyInfo property;
public DataGridSortComparer(IComparer comparer, ListSortDirection sortDirection, string propertyName)
{
this.comparer = comparer;
this.sortDirection = sortDirection;
this.propertyName = propertyName;
}
public int Compare(object x, object y)
{
PropertyInfo property = this.property ?? (this.property = x.GetType().GetProperty(propertyName));
object value1 = property.GetValue(x);
object value2 = property.GetValue(y);
int result = comparer.Compare(value1, value2);
if (sortDirection == ListSortDirection.Descending)
{
result = -result;
}
return result;
}
}
}
}
This should look similar to trilson86's solution as well:
<UserControl.Resources>
<converters:MyComparer x:Key="MyComparer"/>
</UserControl.Resources>
<DataGrid behaviours:DataGridSortBehavior.AllowCustomSort="True" ItemsSource="{Binding MyListCollectionView}">
<DataGrid.Columns>
<DataGridTextColumn Header="Test" Binding="{Binding MyValue}" behaviours:DataGridSortBehavior.Sorter="{StaticResource MyComparer}" />
</DataGrid.Columns>
</DataGrid>
you can use this in case that you adding the columns programatically .
dg_show.Items.SortDescriptions.Add(new System.ComponentModel.SortDescription("val1", System.ComponentModel.ListSortDirection.Descending));
"val1" here is the binding path for the column we added , and you can also using another line as a second sort . like this one .
dg_show.Items.SortDescriptions.Add(new System.ComponentModel.SortDescription("val2", System.ComponentModel.ListSortDirection.Ascending));