当我更新 ObservableCollection 时 GUI 冻结
我有一个显示 ObservableCollection 的 WPF 应用程序。它大约有 182 行,集合内的对象(我们称之为 PositionLight)大约有 70 个要显示的属性。
这些属性中输入数据的所有计算均在第二个线程中进行,该线程将每 20 秒重新计算所有内容,并将列表发送到 WPF 窗口,感谢事件。这样计算不会减慢 GUI 的速度。
List 在与事件一起发送到 GIU 的 EventArgs 的构造函数中转换为 ObservableCollection。
问题是,即使我使用 BeginInvoke 和委托执行以下操作:
myGUICollection = myEventArgsCollection,
GUI 也会冻结 3 到 4 秒...我已经放置了很多 Console.Writeline 来找出瓶颈在哪里,但是看起来冻结将在它离开 BeginInvoke 调用的函数后立即发生。我真的迷失在这里了。
我使用的是带有 2.5Go RAM 的 4 核 PC,所以我不认为这是硬件问题。
你们有想法吗?
一些代码可以让您更好地了解 GUI 中的插入:
public bool myCoreScope_OnCoreCalculationHandler(object myObject, CoreCalculationEventArgs myEventArgs)
{
foreach (PositionLight item in myEventArgs.MyPositionList)
{
lv.Dispatcher.BeginInvoke(new DisplayPositionItemCallBack(DisplayPositionItem), DispatcherPriority.Send, new object[] { item });
}
}
private delegate void DisplayPositionItemCallBack(PositionLight item);
private void DisplayPositionItem(PositionLight item)
{
try
{
MyPositionList.Remove(MyPositionList.First(position => position.ID== item.ID));
}
catch (Exception)
{ }
MyPositionList.Add(item);
}
I have a WPF application that displays an ObservableCollection. It's about 182 rows, and the object (let's call it PositionLight) inside the collection has about 70 properties to display.
All calculation to input data in these properties are made in a second thread which will recalc everything every 20 secondes, and will send a List to the WPF window, thx to an Event. This way calculation doesn't slow down the GUI.
the List is transformed in an ObservableCollection in the constructor of the EventArgs sent with the event to the GIU.
The problem is even when i use a BeginInvoke and a delegate to do:
myGUICollection = myEventArgsCollection
the GUI will be frozen for 3 to 4 seconds... I've put a lot of Console.Writeline to find out where is the bottleneck, but it looks like the freeze will occurs just after it leaves the function called by the BeginInvoke. I'm really lost here.
I'm using a 4 core PC with 2.5Go RAM, so i don't think this is a hardware problem.
Do you guys have an idea?
Some code to give you a better idea of the insert in the GUI:
public bool myCoreScope_OnCoreCalculationHandler(object myObject, CoreCalculationEventArgs myEventArgs)
{
foreach (PositionLight item in myEventArgs.MyPositionList)
{
lv.Dispatcher.BeginInvoke(new DisplayPositionItemCallBack(DisplayPositionItem), DispatcherPriority.Send, new object[] { item });
}
}
private delegate void DisplayPositionItemCallBack(PositionLight item);
private void DisplayPositionItem(PositionLight item)
{
try
{
MyPositionList.Remove(MyPositionList.First(position => position.ID== item.ID));
}
catch (Exception)
{ }
MyPositionList.Add(item);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当您调用 BeginInvoke 时,您正在将 ObservableCollection 的更新编组到 GUI 线程上,因此虽然计算可能发生在单独的线程上,但 UI 的更新却不会。如果您对 GUI 线程调用昂贵的更新,则该线程将必须等待该操作完成。
另一种方法是对集合中的每个项目执行调用,而不是一次调用整个集合,这将使 GUI 有时间在更新之间处理其其他消息。
您可以尝试的另一个选项是设置 ItemsSource 数据绑定的
IsAsync
属性。When you call BeginInvoke you are marshalling the update of the ObservableCollection onto the GUI thread, so while the calculation may happen on a seperate thread the update of the UI does not. If you invoke an expensive update onto the GUI thread, then the thread will have to wait until that operation is completed.
An alternative approach is to perform an invoke for each item in the collection, rather than the whole collection at once, which will give the GUI time to process its other messages between updates.
Another option you could try is to set the
IsAsync
attribute of the ItemsSource data-binding.