DataGridView-通过单击列标题对通用列表进行排序 [英] DataGridView - Sort Generic Lists by Click on Column Headers

查看:88
本文介绍了DataGridView-通过单击列标题对通用列表进行排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

When I assign a List<MyClass> to DataSource of a DataGridView, when I click on column headers, nothing happens and sorting doesn't work; but if I use a DataTable as data source, the sorting works perfect when a header is clicked.

问题是:应该使用哪种收集类型在 DataGridView 中启用排序,就像它与 DataTable 一起工作时一样

The question is: Which kind of collection types should be used to enable sorting in DataGridView just like it works with DataTable when I click on column header?

推荐答案

在数据绑定的DataGridView中排序如何工作

在数据绑定的 DataGridView 中单击列标题时,该列已启用其自动排序功能,首先检查是否后面的列表 DataSource 属性的属性为 IBindingList ,然后使用 SupportsSorting 检查列表是否支持排序。然后,它调用 ApplySort 方法对列表进行排序。

When you click on a column header in a data-bound DataGridView which its automatic sorting is enabled, first it checks if the list behind of the DataSource property is IBindingList, then using SupportsSorting checks if the list supports sorting. Then it calls ApplySort method to sort the list.

当您使用 DataTable 作为网格的数据源,该数据源后面的列表实际上是 DataView ,该实现实现了支持排序的 IBindingList

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

To have automatic support for sorting in a DataGridView, the list should implement IBindingList and its members which are related to sort.

在BindingList中启用排序

要具有 IBindingList 的类型化列表实现(它也支持排序),一个不错的选择是来自 BindingList< T> 。它实现了 IBindingList ,但默认情况下不支持排序。您可以覆盖与排序相关的方法和属性: SupportsSortingCore IsSortedCore SortPropertyCore SortDirectionCore ApplySortCore

To have typed list implementation of IBindingList which also supports sorting, a good option is deriving from BindingList<T>. It implements IBindingList but it doesn't support sorting by default. You can override it's methods and properties which are related to sorting: SupportsSortingCore, IsSortedCore, SortPropertyCore, SortDirectionCore and ApplySortCore.

现有实现

周围有一些实现:

SortableSearchableList< T> ,它发布在 MSDN中文章

如果使用的是实体框架,则 ToBindingList 方法msdn.microsoft.com/zh-cn/library/gg696248(v=vs.113).aspx rel = nofollow noreferrer> Local 属性 DbSet< T> 返回可排序的 BindingList< T>

If you are using Entity Framework, ToBindingList method of the Local property of DbSet<T> returns a sortable BindingList<T>.

这里是从Microsoft内部实现中借用的实现,但做了一些小的更改:

Here is an implementation which is borrowed from Microsoft internal implementations with some small changes:

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

这篇关于DataGridView-通过单击列标题对通用列表进行排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆