DataGridView-通过单击列标题对通用列表进行排序



当我将 List<MyClass>分配给 DataGridView的 CC_1时,当我单击列标题时,什么也不会发生并且排序不起作用;但是,如果我使用 DataTable作为数据源,则单击标题时,排序可实现。

问题是:当我单击列标题时,应使用哪种类型的集合类型在DataGridView中启用排序?

排序如何在数据结合的datagridview

中工作

当您单击启用数据结合的DataGridView中的列标头时,首先检查DataSource属性的列表是否为IBindingList,然后使用SupportsSorting检查列表是否支持排序。然后调用ApplySort方法来对列表进行排序。

当您使用DataTable作为网格的数据源时,数据源背后的列表实际上是DataView,它实现了支持分类的IBindingList

要自动支持DataGridView中的排序,该列表应实现与排序相关的IBindingList及其成员。

在bindingList&lt; t&gt;

中启用排序

要键入IBindingList的列表实现,该列表也支持排序,一个不错的选择是从BindingList<T>派生。它实现了IBindingList,但默认情况下不支持排序。您可以覆盖其与排序相关的方法和属性:DataSource0,IsSortedCoreSortPropertyCoreSortDirectionCoreApplySortCore

现有实现

周围有一些实现:

  • SortableBindingList<T>实现实体框架。

  • SortableSearchableList<T>,该文章在MSDN文章中发表

  • 如果您使用的是实体框架,则Local DbSet<T>ToBindingList CC_29属性返回可排序的BindingList<T>

sortableBindingList

这是一个从Microsoft内部实现中借入的实现,具有一些小更改:

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
public class SortableBindingList<T> : BindingList<T>
{
    private bool _isSorted;
    private ListSortDirection _sortDirection;
    private PropertyDescriptor _sortProperty;
    public SortableBindingList(List<T> list)
        : base(list)
    {
    }
    protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
    {
        if (PropertyComparer.CanSort(prop.PropertyType))
        {
            ((List<T>)Items).Sort(new PropertyComparer(prop, direction));
            _sortDirection = direction;
            _sortProperty = prop;
            _isSorted = true;
            OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
        }
    }
    protected override void RemoveSortCore()
    {
        _isSorted = false;
        _sortProperty = null;
    }
    protected override bool IsSortedCore
    {
        get { return _isSorted; }
    }
    protected override ListSortDirection SortDirectionCore
    {
        get { return _sortDirection; }
    }
    protected override PropertyDescriptor SortPropertyCore
    {
        get { return _sortProperty; }
    }
    protected override bool SupportsSortingCore
    {
        get { return true; }
    }
    internal class PropertyComparer : Comparer<T>
    {
        private readonly IComparer _comparer;
        private readonly ListSortDirection _direction;
        private readonly PropertyDescriptor _prop;
        private readonly bool _useToString;
        public PropertyComparer(PropertyDescriptor prop, ListSortDirection direction)
        {
            if (!prop.ComponentType.IsAssignableFrom(typeof(T)))
            {
                throw new MissingMemberException(typeof(T).Name, prop.Name);
            }
            Debug.Assert(CanSort(prop.PropertyType), "Cannot use PropertyComparer unless it can be compared by IComparable or ToString");
            _prop = prop;
            _direction = direction;
            if (CanSortWithIComparable(prop.PropertyType))
            {
                var property = typeof(Comparer<>).MakeGenericType(new[] { prop.PropertyType }).GetTypeInfo().GetDeclaredProperty("Default");
                _comparer = (IComparer)property.GetValue(null, null);
                _useToString = false;
            }
            else
            {
                Debug.Assert(
                    CanSortWithToString(prop.PropertyType),
                    "Cannot use PropertyComparer unless it can be compared by IComparable or ToString");
                _comparer = StringComparer.CurrentCultureIgnoreCase;
                _useToString = true;
            }
        }
        public override int Compare(T left, T right)
        {
            var leftValue = _prop.GetValue(left);
            var rightValue = _prop.GetValue(right);
            if (_useToString)
            {
                leftValue = leftValue != null ? leftValue.ToString() : null;
                rightValue = rightValue != null ? rightValue.ToString() : null;
            }
            return _direction == ListSortDirection.Ascending
                       ? _comparer.Compare(leftValue, rightValue)
                       : _comparer.Compare(rightValue, leftValue);
        }
        public static bool CanSort(Type type)
        {
            return CanSortWithToString(type) || CanSortWithIComparable(type);
        }
        private static bool CanSortWithIComparable(Type type)
        {
            return type.GetInterface("IComparable") != null ||
                   (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>));
        }
        private static bool CanSortWithToString(Type type)
        {
            return type.Equals(typeof(XNode)) || type.IsSubclassOf(typeof(XNode));
        }
    }
}
public static class EnumerableExtensions
{
    public static BindingList<T> ToSortableBindingList<T>(this IEnumerable<T> source)
    {
        return new SortableBindingList<T>(source.ToList());
    }
}

示例

private void Form1_Load(object sender, EventArgs e)
{
    var list = Enumerable.Range(1, 10)
        .Select(x => new { A = x, B = $"x" })
        .ToSortableBindingList();
    dataGridView1.DataSource = list;
}

最新更新