DataGridView-通过单击列标题对通用列表进行排序 [英] DataGridView - Sort Generic Lists by Click on Column Headers
问题描述
当我将 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中文章
如果使用的是实体框架,则 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屋!