向WPF Datagrid添加大量项目会占用大量CPU时间

时间:2012-11-28 20:27:42

标签: c# data-binding wpfdatagrid inotifycollectionchanged

我正在创建具有一些简单嗅探器功能的应用程序,并显示用户转储的数据包。从转储文件中读取数据包,该文件使用当前流量实时更新,然后将捕获的数据包添加到Datagrid(每个数据包都是新行)。我使用数据绑定从转储读取器获取数据包,它实现了ICollectionChanged接口,因此每个新数据包都会通知Datagrid。 Datagrid使用虚拟化和延迟滚动。几乎一切都运行良好 - 唯一的例外是巨大的CPU消耗。这种CPU利用率是由于我读取所有新数据包(每秒数千个),格式化它们以进行显示以及每个数据包上升的CollectionChanged事件(更新Datagrid)引起的。对软件的要求是用户不必实时查看所有新数据包 - 它们每秒出现数十万,因此没有人会注意到它们。用户只能查看某些数据包并在需要时,可以向下/向上滚动到适当的位置以查看他想要的数据包,并且只有在那种情况下才能从文件中读取数据包。

问题是我希望Datagrid每秒更新一次以显示新数据包到达,最好是通过将滚动条缩放到实际的数据包数,但不需要连续读取,格式化和调用CollectionChanged,因为它需要CPU时间,此外如果用户不滚动条形图,用户也不会看到新的数据包。我被告知到达的数据包的数量,所以我知道所有数据包的数量。

我尝试添加假数据包(从而避免读取和格式化每个新数据包)只是为了强制Datagrid扩展到实际数据包计数。它几乎可以工作,因为CPU使用率下降,数据包仅在我滚动条时读取。但过了一会儿,当新数据包被添加到Datagrid时,当前视图中的行开始随机重复,即 在视图中的第一时刻数据包显示第1,第2,第3,第4,第5,第6等等,但过了一会儿,它们显示为第1,第2,第3,再次显示第1,第2,第3。

我也尝试刷新绑定 - 它工作,但比第一种方法消耗更多的资源,所以我放弃了它。我还尝试刷新Datagrid的listcollectionview - 与刷新绑定一样。

接下来就是当我想在一次调用CollectionChanged

时添加数据包列表
NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, list));

我收到错误,表示不支持Range动作,由PresentationFramework.dll抛出!System.Windows.Data.ListCollectionView.ValidateCollectionChangedEventArgs(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)

所以我不得不为数据包列表中的每个数据包调用CollectionChanged,这也增加了CPU使用率。

总结一下,我想通知Datagrid有新的数据包/行,因此Datagrid滚动条会缩放到数据包的总数,但只有当数据包将从文件中读取时用户滚动栏。

我会非常感谢每一个建议如何解决我的问题。

我刚刚意识到,有一件重要的事情需要提及,对不起,我忘了在开始时告诉它。我的ObservableCollection支持某种数据虚拟化,在内存中我只保留一些必要的数据包。当新数据包到达时,我只是告知我的收集有关新数据包的数量,我不必调用Add方法收集,因为我实际上没有添加任何数据包 - 所以没有实际读取数据包< / strong>即可。 Collection包含有关该时刻的数据包总数的信息,并且只有少量数据包实际存储在内存中,以便网格可以显示它们。数据包仅在必要时即时读取,当它们未显示时,它们将被释放。 但是要告知网格有关新数据包我必须(我不知道如何做另一个,更好的方法)调用CollectionChanged并且在这个调用的参数中我需要提供每个新数据包。而这个对CollectionChanged的调用使得数据包实际上被读取,消耗了什么CPU。 我想重新调整网格,以便滚动条大小可以通知新数据包到达,但无需读取数据包并在每个新数据包中调用CollectionChanged(可能每秒发生一次)。我希望只在滚动条位置改变时才能读取数据包,因此处理每个数据包的昂贵操作只能用于少数当前可见的数据包,而不是每个数据包。

1 个答案:

答案 0 :(得分:0)

如果DataGrid绑定到ObservableCollection。并且每个T包含有关给定数据包的信息,诀窍将是制作&#34; T&#34;类实例化非常快。

现在,您正在创建每个T并计算显示所需的所有信息,因为您要将它们添加到集合中。

它应该只为其构造函数提供足够的信息,以便稍后当用户滚动网格以查看其行时,它可以检索有关该数据包的信息。