为啥在 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 =&gt; X.ID == dataPacket.ID).FirstOrDefault() == null 简化为MessagePacket._jobs.FirstOrDefault(X =&gt; X.ID == dataPacket.ID) == null,然后进一步简化为!MessagePacket._jobs.Any(X =&gt; X.ID == dataPacket.ID)MessagePacket._jobs.All(X =&gt; 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;

【讨论】:

我第一次听说ObservableDictionaryWPF 中可用吗? 它不是框架的一部分,但你可以在互联网上找到实现。 谢谢。我会查看您发送的链接并尝试一下。

以上是关于为啥在 DataGrid 中刷新 ObservableCollection 很慢的主要内容,如果未能解决你的问题,请参考以下文章

在 Silverlight 中刷新 DataGrid

DataGrid 刷新选中问题

WPF中的DataGrid怎么刷新数据

当其 ItemsSource 更改时自动刷新 Datagrid

wpf中,当DataGrid.ItemsSource与ObservableCollection绑定后,值变化时,DataGrid如何刷新?

WPF中,我使用了datagrid,我想请问下当我向数据库添加了新的数据,我该怎么刷新datagrid里面的数据?