【问题标题】:Rapidly removing (and adding) many items to a Canvas in WPF在 WPF 中快速删除(和添加)许多项目到画布
【发布时间】:2012-09-20 13:44:08
【问题描述】:

在我的 WPF 应用程序的某个时刻,一旦我将项目删除和/或添加到画布,UI 线程将锁定 ~0 到 ~500 毫秒(取决于数量)。几项性能测试指出 Canvas.Children.Remove 是主要原因,并且 .Add 也是如此(.Remove 更为严重)。 我同时删除了大约 500 个项目,同时也添加了大约 500 个项目。这大约每秒 10 次会导致问题。

最后,我编写了一个简单的基准测试应用程序,代码如下。

    public MainWindow() {
        InitializeComponent();
        this.Loaded += (object sender, RoutedEventArgs e) => {
            List<Image> a = new List<Image>();
            Stopwatch s = new Stopwatch();
            s.Start();
            for (int i = 0; i < 7500; i++) {
                Image img = new Image();
                Canvas.SetLeft(img, i * 10);
                C.Children.Add(img);
                if (i % 10 == 1)
                    a.Add(img);
            }
            s.Stop();
            long add = s.ElapsedMilliseconds;
            s.Reset();
            s.Start();
            foreach (Image img in a) {
                C.Children.Remove(img);
            }
            s.Stop();
            MessageBox.Show(String.Format("Add: {0}, Remove: {1}.", add, s.ElapsedMilliseconds));
        };
    }

这给出了以下结果(围绕这个,每次我运行它):

Add: 174, Remove: 156.

请记住,只有 750 项被删除,而 7500 项被添加。

这个过程有点繁重,但我不希望用户界面(主要是ScrollViewer)在执行此操作时锁定。我面临的另一个问题是我不能将它“移动”到另一个 Thread,因为我无法从那个特定的 Thread 控制 UI。

如何改进这个过程?或者有没有办法“随着时间的推移”动态添加/删除项目,所以它不会挂断?

谢谢,

~Tgys

【问题讨论】:

  • 如此频繁地添加或删除这么多项目,您想做什么?绘制位图并显示它会更快或更容易吗?
  • @JoshC。很快检查虚拟化,似乎很有趣。
  • @akton 我正在构建某种 2D 编辑器(非基于磁贴,之前找到了一篇关于虚拟化的文章),这个工作空间非常大,所以我想动态加载/卸载图像从记忆里。 (显示大约 1000 万张图像(实际上可能更多,粗略猜测)“超出滚动范围”并没有真正起作用;))。
  • 为了更清楚一点,虚拟化并不能帮助您将数据加载到应用程序中。虚拟化使您免于渲染不在视图中的内容。如果您尝试仅按需将数据加载到应用程序中,则可能需要研究延迟加载技术。

标签: c# wpf performance wpf-controls uielementcollection


【解决方案1】:

如果您将其拆分为新线程并每隔 20 毫秒左右将工作分派到 UI 线程中会怎样?这样您就不会完全锁定 UI。所以用户可以同时做其他事情。

我知道的其他事情: 有 AddRange 方法吗?也许您可以一次添加所有项目。这样,理论上只会发生一次布局更新,从而将时间缩短为零。

删除也是如此。见Canvas.Children.RemoveRange(a);

【讨论】:

  • 您的第一个建议可能对我有用,将对此进行一些实验。然而,我最担心的是,每当有更多的项目要删除/添加时,会花费大量时间,“堵塞”队列。您的第二个建议涉及一个问题:我删除“随机”项目,并添加“随机”项目。那些没有被索引,有时添加的项目的一部分被删除了,我猜是把索引弄乱了。
  • 我不太明白。真的没关系。将列表 a 输入到 RemoveRange 中,它将删除它可以删除的所有项目。仅更新一次布局。另外,获取dotTrace,这会更准确。它在内部显示瓶颈在哪里。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-02
  • 2014-12-23
  • 2018-12-23
  • 1970-01-01
相关资源
最近更新 更多