当我将 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
,但默认情况下不支持排序。您可以覆盖其与排序相关的方法和属性:DataSource
0,IsSortedCore
,SortPropertyCore
,SortDirectionCore
和ApplySortCore
。
现有实现
周围有一些实现:
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;
}