2016-03-30 3 views
3

У меня есть DataGrid со следующей колонкой, которая связывается с enum с именем Type с конвертером.Сортировка datagrid WPF для перечисления с конвертером

<DataGridTextColumn Header="Type" 
Binding="{Binding Path=Type,Converter={StaticResource EnumStringConverter}}" /> 

Он отображает преобразованные значения должным образом. Но он не справляется с сортировкой.

Ascending sort goes wrong

descending sort goes wrong too!

Правильный порядок для сортировки по возрастанию должно быть Cash, Debt Security and Gold или назад для сортировки по убыванию.

Enum определяется как

enum SomeType 
{ 
    Cash = 0, 
    Gold = 1, 

    // few more values ... 

    DebtSecurity = 6, 
} 

Я также попытался использовать SortMemberPath="Type" для столбца, но по-прежнему дает тот же результат. Я пропустил что-то очень основное здесь?

+0

Ваша сетка по-прежнему сортирует перечисление, а не строку. Возможно, вместо конвертера, создайте другое свойство в своей модели viewmodel, которое преобразует перечисление в строку и использует это вместо –

+0

Да, я искал объяснение, почему это происходит? и больше ориентированного на XAML решение. – bit

ответ

1

После подробного поиска и поиска ответов в деталях я мог бы объединить доступные ответы, чтобы решить общее требование такого рода.

Итак, если вы хотите включить сортировку по преобразованным значениям enum.

1) Добавьте следующий conveerted-перечислимый-сортировочного класс

/// <summary> 
/// Allows a grid to be sorted based upon the converted value. 
/// </summary> 
public static class GridEnumSortingBehavior 
{ 
    #region Properties 

    public static readonly DependencyProperty UseBindingToSortProperty = 
     DependencyProperty.RegisterAttached("UseBindingToSort", typeof(bool), typeof(GridEnumSortingBehavior), 
              new PropertyMetadata(UseBindingToSortPropertyChanged)); 

    #endregion 

    public static void SetUseBindingToSort(DependencyObject element, bool value) 
    { 
     element.SetValue(UseBindingToSortProperty, value); 
    } 

    #region Private events 

    private static void UseBindingToSortPropertyChanged(DependencyObject element, DependencyPropertyChangedEventArgs e) 
    { 
     var grid = element as DataGrid; 
     if (grid == null) 
     { 
      return; 
     } 

     var canEnumSort = (bool)e.NewValue; 
     if (canEnumSort) 
     { 
      grid.Sorting += GridSorting; 
     } 
     else 
     { 
      grid.Sorting -= GridSorting; 
     } 
    } 

    private static void GridSorting(object sender, DataGridSortingEventArgs e) 
    { 
     var boundColumn = e.Column as DataGridBoundColumn; 
     if (boundColumn == null) 
     { 
      return; 
     } 

     // Fetch the converter,binding prop path name, if any 
     IValueConverter converter = null; 
     string bindingPropertyPath = null; 
     if (boundColumn.Binding == null) 
     { 
      return; 
     } 
     var binding = boundColumn.Binding as Binding; 
     if (binding == null || binding.Converter == null) 
     { 
      return; 
     } 
     converter = binding.Converter; 
     bindingPropertyPath = binding.Path.Path; 
     if (converter == null || bindingPropertyPath == null) 
     { 
      return; 
     } 

     // Fetch the collection 
     var dataGrid = (DataGrid)sender; 
     var lcv = (ListCollectionView)CollectionViewSource.GetDefaultView(dataGrid.ItemsSource); 
     if (lcv == null || lcv.ItemProperties == null) 
     { 
      return; 
     } 

     // Fetch the property bound to the current column (being sorted) 
     var bindingProperty = lcv.ItemProperties.FirstOrDefault(prop => prop.Name == bindingPropertyPath); 
     if (bindingProperty == null) 
     { 
      return; 
     } 

     // Apply custom sort only for enums types 
     var bindingPropertyType = bindingProperty.PropertyType; 
     if (!bindingPropertyType.IsEnum) 
     { 
      return; 
     } 

     // Apply a custom sort by using a custom comparer for enums 
     e.Handled = true; 
     ListSortDirection directionToSort = boundColumn.SortDirection != ListSortDirection.Ascending 
               ? ListSortDirection.Ascending 
               : ListSortDirection.Descending; 
     boundColumn.SortDirection = directionToSort; 
     lcv.CustomSort = new ConvertedEnumComparer(converter, directionToSort, bindingPropertyType, bindingPropertyPath); 
    } 

    #endregion 
} 

2) Добавление пользовательского компаратора, который сравнивает значение перечислений на основе их преобразованных значений

/// <summary> 
/// Converts the value of enums and then compares them 
/// </summary> 
public class ConvertedEnumComparer : IComparer 
{ 

    #region Fields 

    private readonly Type _enumType; 
    private readonly string _enumPropertyPath; 
    private readonly IValueConverter _enumConverter; 
    private readonly ListSortDirection _directionToSort; 

    #endregion 

    public ConvertedEnumComparer(IValueConverter enumConverter, ListSortDirection directionToSort, Type enumType, string enumPropertyPath) 
    { 
     _enumType = enumType; 
     _enumPropertyPath = enumPropertyPath; 
     _enumConverter = enumConverter; 
     _directionToSort = directionToSort; 
    } 

    #region IComparer implementation 

    public int Compare(object parentX, object parentY) 
    { 
     if (!_enumType.IsEnum) 
     { 
      return 0; 
     } 

     // extract enum names from the parent objects 
     var enumX = TypeDescriptor.GetProperties(parentX)[_enumPropertyPath].GetValue(parentX); 
     var enumY = TypeDescriptor.GetProperties(parentY)[_enumPropertyPath].GetValue(parentY); 

     // convert enums 
     object convertedX = _enumConverter.Convert(enumX, typeof(string), null, Thread.CurrentThread.CurrentCulture); 
     object convertedY = _enumConverter.Convert(enumY, typeof(string), null, Thread.CurrentThread.CurrentCulture); 

     // compare the converted enums 
     return _directionToSort == ListSortDirection.Ascending 
           ? Comparer.Default.Compare(convertedX, convertedY) 
           : Comparer.Default.Compare(convertedX, convertedY) * -1; 
    } 

    #endregion 
} 

3) Наконец, чтобы использовать это на любом DataGrid просто пометьте поведение, что True

<DataGrid ItemsSource="{Binding YourDataCollectionWithEnumProperty}" 
yourbehaviors:GridEnumSortingBehavior.UseBindingToSort="True" > 
Смежные вопросы