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

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

问题描述

当我将 List 分配给 DataGridViewDataSource 时,当我单击列标题时,没有任何反应并且排序不会不工作;但是,如果我使用 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.它实现了 IBindingList 但它默认不支持排序.您可以覆盖与排序相关的方法和属性:SupportsSortingCoreIsSortedCoreSortPropertyCoreSortDirectionCore 和 <代码>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.

现有实现

周围有一些实现:

  • T> 实体框架中使用的实现.

  • SortableBindingList<T> implementation which is used in Entity Framework.

SortableSearchableList 发布在 MSDN 文章

如果您使用实体框架,ToBindingList 方法的 Local DbSet 属性返回一个可排序的 BindingList>.

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天全站免登陆