Sort on multiple columns in WPF datagrid

20,990

Solution 1

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 named CanUserSortColumns

enter image description here

  • Add this code to the grid PreviewMouseLeftButtonUp 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.

Solution 2

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.

Share:
20,990

Related videos on Youtube

Tom
Author by

Tom

Updated on July 09, 2022

Comments

  • Tom
    Tom almost 2 years

    How can I set up my WPF datagrid to sort on multiple columns similar to having two sortable columns, clicking on the header of the first column for a primary sort and then SHIFT clicking on the header of the second column for a secondary sort. I would like the multiple column sort to happen automatically when the user clicks on the header of the first column without having to SHIFT click on the second column header. Is there a way to do this entirely in the xaml? If not how can I do this in the code behind? Currently using VB.Net but a C# snippet is acceptable if you have one. Thanks!

  • Dan J
    Dan J almost 13 years
    The OP asked how to allow a user to sort a grid by clicking on multiple column headers, not how to programmatically sort the underlying collection once.
  • Issam Ali
    Issam Ali almost 13 years
    @djacobson I think I read the Question well, he write: "Is there a way to do this entirely in the xaml?"
  • Issam Ali
    Issam Ali almost 13 years
    @djacobson besides by clicking on multiple column headers the grid is automatically sort on the selected columns.
  • Issam Ali
    Issam Ali almost 13 years
    @djacobson due this explanation I think your downvote is unfair.
  • Tom
    Tom almost 13 years
    Correct @djacobson. I was aware of the above method for sorting the underlying view but this does nothing to the sorting behavior of the header click. Also, to be clear I know how to sort based on multiple header clicks (click, SHIFT click) what I want to find out is how to sort on two columns with only one header click.
  • Issam Ali
    Issam Ali almost 13 years
    @Tom so what about my answer? does it help?
  • Tom
    Tom almost 13 years
    @IssamAli I want to find out how to sort on a primary and secondary column by ONLY clicking on the primary column header. Your solution describes a method for sorting based on two columns but has nothing to do with the datagrid header click so it would be wrong to mark your solution as the answer although it is relevant.
  • Issam Ali
    Issam Ali almost 13 years
    Ok! what .Net version you use?