简体   繁体   English

对于具有转换器的枚举,WPF数据网格排序失败

[英]WPF datagrid sorting fails for enum with converter

I have a DataGrid with the following column, which binds to an enum named Type with a converter. 我有一个带有以下列的DataGrid ,它使用转换器绑定到名为Typeenum

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

It displays the converted values properly. 它正确显示转换后的值。 But it fails at sorting. 但它在排序方面失败了。

升序排序出错了

降序排序也出错了!

The correct order for ascending sort should have been Cash, Debt Security and Gold or reverse for descending sort. 升序排序的正确顺序应该是Cash, Debt Security and Gold或者是降序排序。

The Enum is defined as 枚举定义为

enum SomeType
{   
    Cash = 0,
    Gold = 1,

    // few more values ...

    DebtSecurity = 6,
}

I have also tried to use the SortMemberPath="Type" for the column but still gives the same result. 我也尝试使用SortMemberPath="Type"作为列,但仍然给出相同的结果。 Am I missing something very basic here? 我错过了一些非常基本的东西吗?

After extensive searching and find some answers in parts, I could merge the available answers to solve a generic requirement of this sort. 经过广泛的搜索并找到部分答案,我可以合并可用的答案来解决这种通用要求。

So, if you want to enable sorting by your enum's converted values. 因此,如果您想通过枚举转换后的值启用排序。

1) Add the following conveerted-enum-sorting class 1)添加以下的enerted-enum-sorting类

/// <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) Add a custom comparer that compares the enum values based on their converted values 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) Finally to use this on any DataGrid simply mark the behavior as True 3)最后在任何DataGrid上使用它只需将行为标记为True

<DataGrid ItemsSource="{Binding YourDataCollectionWithEnumProperty}" 
yourbehaviors:GridEnumSortingBehavior.UseBindingToSort="True" >

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM