Sort on multiple columns in WPF datagrid

后端 未结 2 2023
心在旅途
心在旅途 2020-12-05 04:56

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 S

相关标签:
2条回答
  • 2020-12-05 05:39

    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.

    0 讨论(0)
  • 2020-12-05 05:56

    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.

    0 讨论(0)
提交回复
热议问题