Sort on multiple columns in WPF datagrid Sort on multiple columns in WPF datagrid wpf wpf

Sort on multiple columns in WPF datagrid


You can do this by adding System.ComponentModel namespace like this:

xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"

then inside the CollectionViewSource XAML add new SortDescriptions like this:

<CollectionViewSource … >            <CollectionViewSource.SortDescriptions>                <scm:SortDescription PropertyName="Column1"/>                <scm:SortDescription PropertyName="Column2"/>            </CollectionViewSource.SortDescriptions></CollectionViewSource>

this will sort datagrid on column1,column2.

Edit:

also doing this using C# code behind is pretty easy :

    private void btnSort_Click(object sender, RoutedEventArgs e)    {        System.Windows.Data.CollectionViewSource myViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("The_ViewSource_Name")));        myViewSource.SortDescriptions.Add(new SortDescription("Column1", ListSortDirection.Ascending));        myViewSource.SortDescriptions.Add(new SortDescription("Column2", ListSortDirection.Ascending));    }

Edit2:

Workaround can be made to catch the column header left mouse click event and prevent the grid from sort on that column like this:

  • Disable grid property namedCanUserSortColumns

enter image description here

  • Add this code to the gridPreviewMouseLeftButtonUp event :

    private void myDataGrid_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e){    DependencyObject dep = (DependencyObject)e.OriginalSource;    while ((dep != null) &&    !(dep is DataGridCell) &&    !(dep is DataGridColumnHeader))    {        dep = VisualTreeHelper.GetParent(dep);    }    if (dep == null)        return;    if (dep is DataGridColumnHeader)    {        DataGridColumnHeader columnHeader = dep as DataGridColumnHeader;        // check if this is the wanted column        if (columnHeader.Column.Header.ToString() == "The_Wanted_Column_Title")        {            System.Windows.Data.CollectionViewSource myViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("myViewSource")));            myViewSource.SortDescriptions.Clear();            myViewSource.SortDescriptions.Add(new SortDescription("Column1", ListSortDirection.Ascending));            myViewSource.SortDescriptions.Add(new SortDescription("Column2", ListSortDirection.Ascending));        }        else        {            //usort the grid on clicking on any other columns, or maybe do another sort combination            System.Windows.Data.CollectionViewSource myViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("myViewSource")));            myViewSource.SortDescriptions.Clear();        }    }}

You can modify and expand this code to achieve your requirements.


I hope this will help others. My solution keep the default sort functionality and allow sorting on multiple columns.

Put a sorting event on your datagrid

<DataGrid x:Name="dataGridName" Sorting="dataGridName_Sorting">

And now in your code behind

private void dataGridName_Sorting(object sender, DataGridSortingEventArgs e){    var dgSender = (DataGrid) sender;    var cView = CollectionViewSource.GetDefaultView(dgSender.ItemsSource);    //Alternate between ascending/descending if the same column is clicked     ListSortDirection direction = ListSortDirection.Ascending;    if (cView.SortDescriptions.FirstOrDefault().PropertyName == e.Column.SortMemberPath)        direction = cView.SortDescriptions.FirstOrDefault().Direction == ListSortDirection.Descending ? ListSortDirection.Ascending : ListSortDirection.Descending;    cView.SortDescriptions.Clear();    AddSortColumn((DataGrid)sender, e.Column.SortMemberPath, direction);    //To this point the default sort functionality is implemented    //Now check the wanted columns and add multiple sort     if (e.Column.SortMemberPath == "WantedColumn")    {        AddSortColumn((DataGrid)sender, "SecondColumn", direction);    }    e.Handled = true;}private void AddSortColumn(DataGrid sender, string sortColumn, ListSortDirection direction){    var cView = CollectionViewSource.GetDefaultView(sender.ItemsSource);    cView.SortDescriptions.Add(new SortDescription(sortColumn, direction));    //Add the sort arrow on the DataGridColumn    foreach (var col in sender.Columns.Where(x => x.SortMemberPath == sortColumn))    {        col.SortDirection = direction;    }}

The sortDirection on the DataGridColumn allow showing the arrow on the grid.