当我更新 ObservableCollection 时 GUI 冻结

发布于 2024-09-28 07:18:46 字数 1281 浏览 5 评论 0原文

我有一个显示 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

太傻旳人生 2024-10-05 07:18:46

当您调用 BeginInvoke 时,您正在将 ObservableCollection 的更新编组到 GUI 线程上,因此虽然计算可能发生在单独的线程上,但 UI 的更新却不会。如果您对 GUI 线程调用昂贵的更新,则该线程将必须等待该操作完成。

另一种方法是对集合中的每个项目执行调用,而不是一次调用整个集合,这将使 GUI 有时间在更新之间处理其其他消息。

var list = GetCollection();
foreach (var item in list)
{
    Dispatcher.BeginInvoke(new Action(() => myGuiCollection.Add(item)));
}

您可以尝试的另一个选项是设置 ItemsSource 数据绑定的 IsAsync 属性。

<ListBox ItemsSource="{Binding myGuiCollection, IsAsync=True}" />

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.

var list = GetCollection();
foreach (var item in list)
{
    Dispatcher.BeginInvoke(new Action(() => myGuiCollection.Add(item)));
}

Another option you could try is to set the IsAsync attribute of the ItemsSource data-binding.

<ListBox ItemsSource="{Binding myGuiCollection, IsAsync=True}" />
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文