После подробного поиска и поиска ответов в деталях я мог бы объединить доступные ответы, чтобы решить общее требование такого рода.
Итак, если вы хотите включить сортировку по преобразованным значениям 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" >
Ваша сетка по-прежнему сортирует перечисление, а не строку. Возможно, вместо конвертера, создайте другое свойство в своей модели viewmodel, которое преобразует перечисление в строку и использует это вместо –
Да, я искал объяснение, почему это происходит? и больше ориентированного на XAML решение. – bit