WPF DataGrid CustomSort for each Column

后端 未结 10 1479
庸人自扰
庸人自扰 2020-12-01 01:56

I have a WPF DataGrid bound to a CollectionViewSource that encapsulates an ObservableCollection. This CollectionViewSource has two main objectives:

1) To group each

10条回答
  •  隐瞒了意图╮
    2020-12-01 02:28

    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;
                }
            }
        }
    }
    

    Your Xaml

    This should look similar to trilson86's solution as well:

    
        
    
    
        
            
        
    
    

提交回复
热议问题