Mat*_*eid 11 .net sorting data-binding bindinglist winforms
我BindingList<T>在我的Windows窗体中使用了一个包含" IComparable<Contact>"联系人对象列表的窗体.现在我希望用户能够按网格中显示的任何列进行排序.
在线MSDN上有一种描述如何实现基于BindingList<T>允许排序的自定义集合的方法.但是,是否有一个Sort-event或者某些东西可以在DataGridView中捕获(或者,甚至更好,在BindingSource上)以使用自定义代码对底层集合进行排序?
我真的不喜欢MSDN描述的方式.另一种方法是我可以轻松地将LINQ查询应用于集合.
Mat*_*eid 25
我用谷歌搜索并尝试了更多的时间......
到目前为止,.NET中没有内置方法.您必须基于实现自定义类BindingList<T>.自定义数据绑定,第2部分(MSDN)中描述了一种方法.我最终生成了一个不同的ApplySortCore-method 实现,以提供一个与项目无关的实现.
protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
{
List<T> itemsList = (List<T>)this.Items;
if(property.PropertyType.GetInterface("IComparable") != null)
{
itemsList.Sort(new Comparison<T>(delegate(T x, T y)
{
// Compare x to y if x is not null. If x is, but y isn't, we compare y
// to x and reverse the result. If both are null, they're equal.
if(property.GetValue(x) != null)
return ((IComparable)property.GetValue(x)).CompareTo(property.GetValue(y)) * (direction == ListSortDirection.Descending ? -1 : 1);
else if(property.GetValue(y) != null)
return ((IComparable)property.GetValue(y)).CompareTo(property.GetValue(x)) * (direction == ListSortDirection.Descending ? 1 : -1);
else
return 0;
}));
}
isSorted = true;
sortProperty = property;
sortDirection = direction;
}
Run Code Online (Sandbox Code Playgroud)
使用这个,您可以按任何实现的成员进行排序IComparable.
Sor*_*scu 18
然而,虽然这为低数据量提供了出色的结果,但在处理大数据量时,由于反射,性能不是很好.
我用一组简单的数据对象运行测试,计算100000个元素.按整数类型属性排序大约需要1分钟.我将进一步细节的实现将此更改为~200ms.
基本思想是使强类型比较受益,同时保持ApplySortCore方法的通用性.以下内容将通用比较委托替换为对派生类中实现的特定比较器的调用:
SortableBindingList <T>中的新增内容:
protected abstract Comparison<T> GetComparer(PropertyDescriptor prop);
Run Code Online (Sandbox Code Playgroud)
ApplySortCore更改为:
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
List<T> itemsList = (List<T>)this.Items;
if (prop.PropertyType.GetInterface("IComparable") != null)
{
Comparison<T> comparer = GetComparer(prop);
itemsList.Sort(comparer);
if (direction == ListSortDirection.Descending)
{
itemsList.Reverse();
}
}
isSortedValue = true;
sortPropertyValue = prop;
sortDirectionValue = direction;
}
Run Code Online (Sandbox Code Playgroud)
现在,在派生类中,必须为每个可排序属性实现比较器:
class MyBindingList:SortableBindingList<DataObject>
{
protected override Comparison<DataObject> GetComparer(PropertyDescriptor prop)
{
Comparison<DataObject> comparer;
switch (prop.Name)
{
case "MyIntProperty":
comparer = new Comparison<DataObject>(delegate(DataObject x, DataObject y)
{
if (x != null)
if (y != null)
return (x.MyIntProperty.CompareTo(y.MyIntProperty));
else
return 1;
else if (y != null)
return -1;
else
return 0;
});
break;
// Implement comparers for other sortable properties here.
}
return comparer;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这种变体需要更多的代码,但是,如果性能是一个问题,我认为值得付出努力.
我知道所有这些答案在撰写时都很好.可能他们仍然是.我正在寻找类似的东西,并找到了一个替代解决方案,将任何列表或集合转换为可排序BindingList<T>.
以下是重要的片段(下面分享了完整示例的链接):
void Main()
{
DataGridView dgv = new DataGridView();
dgv.DataSource = new ObservableCollection<Person>(Person.GetAll()).ToBindingList();
}
Run Code Online (Sandbox Code Playgroud)
此解决方案使用Entity Framework库中提供的扩展方法.因此,在继续进行之前,请考虑以下事项:
如您所见,您可以通过单击DataGridView控件上的列标题对所有四列不同数据类型进行排序.
那些没有LINQPad的人,仍然可以下载查询并用记事本打开它,看看完整的样本.
| 归档时间: |
|
| 查看次数: |
25036 次 |
| 最近记录: |