为啥在 DataGrid 中刷新 ObservableCollection 很慢
Posted
技术标签:
【中文标题】为啥在 DataGrid 中刷新 ObservableCollection 很慢【英文标题】:Why is it slow to refresh ObservableCollection in DataGrid为什么在 DataGrid 中刷新 ObservableCollection 很慢 【发布时间】:2021-12-08 21:43:34 【问题描述】:我需要每秒处理来自总共 80 个不同 ID 的 4000 个消息包。我有一个DataGrid
。我有ObservableCollection
绑定到DataGrid。我尝试了 2 种方法来刷新 UI 而不会冻结。我都没有成功。
1.方式
如果有来自不同 ID 的消息,我会将其添加到我的收藏中。如果它来自同一个ID,我删除旧的并获取新的。
if (MessagePacket._jobs.Where(X => X.ID == dataPacket.ID).FirstOrDefault() == null)
MessagePacket._jobs.Add(dataPacket);
else
for (int x = 0; x < MessagePacket._jobs.Count; x++)
if (MessagePacket._jobs[x].ID == dataPacket.ID)
MessagePacket._jobs.RemoveAt(x);
MessagePacket._jobs.Add(dataPacket);
2.Way
我正在修改数据而不删除它并刷新集合。
注意:我尝试每 50 毫秒刷新一次集合,而不是在每次打包后刷新一次。还是很慢。
if (MessagePacket._jobs.Where(X => X.ID == dataPacket.ID).FirstOrDefault() == null)
MessagePacket._jobs.Add(dataPacket);
else
for (int x = 0; x < MessagePacket._jobs.Count; x++)
if (MessagePacket._jobs[x].ID == dataPacket.ID)
MessagePacket._jobs[x].DLC = dataPacket.DLC;
MessagePacket._jobs[x].RTR = dataPacket.RTR;
MessagePacket._jobs[x].IDE = dataPacket.IDE;
MessagePacket._jobs[x].Byte0 = dataPacket.Byte0;
MessagePacket._jobs[x].Byte1 = dataPacket.Byte1;
MessagePacket._jobs[x].Byte2 = dataPacket.Byte2;
MessagePacket._jobs[x].Byte3 = dataPacket.Byte3;
MessagePacket._jobs[x].Byte4 = dataPacket.Byte4;
MessagePacket._jobs[x].Byte5 = dataPacket.Byte5;
MessagePacket._jobs[x].Byte6 = dataPacket.Byte6;
MessagePacket._jobs[x].Byte7 = dataPacket.Byte7;
MessagePacket._jobs[x].Time = DateTime.Now.ToString("HH:mm:ss");
CollectionViewSource.GetDefaultView(MessagePacket._jobs).Refresh();
如何在不冻结用户界面的情况下加快进程。或者你能展示另一种方式吗?从现在开始谢谢你。
【问题讨论】:
这是 WPF、UWP 还是 Windows.Forms,因为答案可能不同? 50 毫秒的刷新率对最终用户是否有价值?你可以把它限制在视觉上更容易消化的东西。 冻结是什么意思?完全无响应,或在响应/无响应状态之间切换?那么意识到当你真正刷新数据时,ui线程将在整个过程中被阻塞?所以例如。如果你的进程需要 10 毫秒并且你每 50 毫秒执行一次,它会每 50 毫秒冻结 10 毫秒。 请注意,您可以将MessagePacket._jobs.Where(X => X.ID == dataPacket.ID).FirstOrDefault() == null
简化为MessagePacket._jobs.FirstOrDefault(X => X.ID == dataPacket.ID) == null
,然后进一步简化为!MessagePacket._jobs.Any(X => X.ID == dataPacket.ID)
或MessagePacket._jobs.All(X => X.ID != dataPacket.ID)
。如果您使用 VS 进行开发,“Roslynator”插件将为您提供有关这些简化的提示。
试试MessagePacket._jobs[x] = dataPacket;
而不是复制所有数据。您不需要实现 INotifypropertyChanged ro call Refresh()。
【参考方案1】:
这样的东西应该更有效率:
var p = MessagePacket._jobs.FirstOrDefault(x => x.ID == dataPacket.ID);
if (p == null)
MessagePacket._jobs.Add(dataPacket);
else
int i = MessagePacket._jobs.IndexOf(p);
MessagePacket._jobs[i] = dataPacket;
你也可以考虑把_jobs
变成ObservableDictionary,这样你就可以简单地写了
MessagePacket._jobs[dataPacket.ID] = dataPacket;
【讨论】:
我第一次听说ObservableDictionary
在WPF
中可用吗?
它不是框架的一部分,但你可以在互联网上找到实现。
谢谢。我会查看您发送的链接并尝试一下。以上是关于为啥在 DataGrid 中刷新 ObservableCollection 很慢的主要内容,如果未能解决你的问题,请参考以下文章
当其 ItemsSource 更改时自动刷新 Datagrid
wpf中,当DataGrid.ItemsSource与ObservableCollection绑定后,值变化时,DataGrid如何刷新?