交换 BindingList<SomeClass> 元素需要很多时间,为啥会这样,我该怎么办?
Posted
技术标签:
【中文标题】交换 BindingList<SomeClass> 元素需要很多时间,为啥会这样,我该怎么办?【英文标题】:Swapping BindingList<SomeClass> elements takes a lot of time, why is that and what should I do?交换 BindingList<SomeClass> 元素需要很多时间,为什么会这样,我该怎么办? 【发布时间】:2013-05-17 21:16:21 【问题描述】:我在写一个小的C#应用程序主要是为了好玩,并且有一个DataGridView来显示一些数据,它绑定到BindingList。从我决定让表格可排序的那一刻起,乐趣就开始了,这就是使用 BindingList 的原因。据我了解,BindingList 中没有对此的标准实现,但 msdn 有涵盖此的文章 (about implementing sort and find for BindingList)。长话短说,它们的实现中很少有会引起麻烦的行:
SomeClass tmp;
for(...)
tmp = this[i]; //fast
this[i] = this[position]; //slow
this[position] = tmp; //slow
正如 cmets 所示,第一个任务不需要太多时间,但其他两个确实很慢。我不明白它背后的原因,但因为它排序列表 50 左右的元素大约需要两秒钟。 好吧,我可以使用一些解决方法,但它似乎有点难看。此外,我真的很想知道是什么导致了这种行为。
【问题讨论】:
【参考方案1】:之所以会变慢,是因为赋值会导致绑定到该列表的任何内容重绘(例如,DataGridView)。
您应该修改您的排序方法以在更改列表时禁用引发事件。
var origRaiseEvents = this.RaiseListChangedEvents;
this.RaiseListChangedEvents = false;
try
// here goes your original code.
finally
this.RaiseListChangedEvents = origRaiseEvents;
【讨论】:
我注意到,如果原始代码没有返回,那么“finally”并不是真正必要的。 (我的神通感应到你的反对:假设有一个未处理的异常。好吧,假设有一个未处理的异常;程序即将崩溃并因未知原因而死!这真的是开始摆弄事件处理的好时机吗?其他物体的状态?你打开厨房的灯,炸弹在地下室爆炸,你真的认为“让我们确保我们总是在建筑物倒塌之前关掉那盏灯”?) 只要不从自定义代码调用排序,就可能出现这种情况。如果处理异常的组件使用 BindingList 来显示诸如“数据不可用,因为...”之类的消息,而不是关闭整个应用程序怎么办? 啊,现在finally 有了很好的用处。好点。然而,在这种情况下,异常将是 handled 异常。所以我撤回了我之前的声明,并将其替换为“A finally 不是真的必要,除非原始代码返回,或者如果有一个预期的异常将在更高级别处理。”【参考方案2】:如果这是BindingList
,主要问题是DataGridView
会在您每次在BindingList
中设置任何内容时尝试更新。这意味着您标记为慢的两行很可能本身并不慢,而是很慢,因为它们触发了 DataGridView
刷新,这意味着它在排序操作中刷新了很多次。
您可以通过封装 BindingList
而不是对其进行子类化来解决此问题,并且在排序期间不引发事件,而是等到排序完成,然后刷新整个列表。
【讨论】:
嗯,这听起来很可能,但我不确定情况是否如此。 msdn 文章指出,我必须在排序函数结束时调用“ListChanged”事件,以便所有绑定的控件都会刷新。我认为这意味着它们不会刷新,即使在分配时也是如此。 @Michael232 如果您在索引上使用 BindingList 的设置器,则会引发更改的事件。您应该能够自己订阅 ListChanged 事件并进行验证。 @Michael232 除非您将RaiseListChangedEvents
明确设置为 false,否则每个分配都会引发该事件。以上是关于交换 BindingList<SomeClass> 元素需要很多时间,为啥会这样,我该怎么办?的主要内容,如果未能解决你的问题,请参考以下文章
BindingList<T>.Sort() 表现得像 List<T>.Sort()
是啥导致 BindingList<T> 中的 ListChangedType.ItemMoved ListChange 事件?