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
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.