在将多个UIElements添加到画布时,如何保持UI响应?

时间:2014-07-23 15:26:46

标签: c# wpf performance user-interface wpf-controls

我有多达70000个Shape派生对象要添加到Canvas中。显然这会导致UI无响应,在我的情况下大约20秒。我尝试使用Dispatcher方法来尝试克服这个问题,但我仍然遇到问题。

我实施它的第一种方式是这样的:

foreach (var shape in ShapeList)
{
    Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
            {
                drawingCanvas.Children.Add(shape);
            }));
}

这确实使得UI响应,但在不利方面,它需要永远(如10分钟?)才能完全添加所有形状。它也会在添加时立即显示Shape。

我实施的第二种方式是:

Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
            {
                foreach (var shape in ShapeList)
                {
                    drawingCanvas.Children.Add(shape);
                }
            }));

而且这似乎与不使用调度程序具有相同的效果。

我已经在一个单独的线程上尝试了两种实现,并且与主线程没有区别。此外,我必须将它们全部添加为单独的Shape对象,因为它们中的每一个都必须支持单个MouseClickEvents,因此我没有使用drawingVisual。

那么有什么方法可以让主窗口保持响应,同时仍然保持添加过程相对较快?

感谢。

*编辑 我知道CanvasVirtualization,但目前对我来说似乎有点复杂。有没有其他方法可以使用?

2 个答案:

答案 0 :(得分:2)

使用Dispatcher提到的两个问题相当容易解决或减轻。

  1. 剧烈减速(20秒 - > 10分钟)和
  2. 形状添加零碎
  3. 对于1),您可以通过批量添加项目而不是一次一个地添加项目来加快流程,同时仍保持响应性。对于2),一个简单的解决方案就是隐藏画布,并在完成绘图时显示它。

    这样的事情:

    // group shapes into batches
    const int batchSize = 100;
    var batches = ShapeList.Select((item, index) => new { index = index, item = item })
        .GroupBy(item => item.index / batchSize)
        .ToArray();
    
    // function to create a local closure for each batch
    Action<int> addBatch = batchNumber => {
        var batch = batches[batchNumber];
        Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
        {
            foreach (var shape in batch)
            {
                drawingCanvas.Children.Add(shape.item);
            };
            if (batchNumber >= batches.Length - 1)
                drawingCanvas.Visibility = Visibility.Visible;
        }));
    };
    
    drawingCanvas.Visibility = Visibility.Collapsed;
    for (int i=0 ; i < batches.Length ; i++)
    {
        addBatch(i);
    }
    

答案 1 :(得分:0)

理想情况下,您应该使用虚拟化技术,只绘制实际可见的内容,而不是绘制所有70,000个项目。 MSDN上有一个博客,其中包含VirtualCanvas类的源代码,如果您已经使用Canvas,它几​​乎可以用于任何用途。

请注意 - 虚拟化具有一些特定条件,可以虚拟化项目。

http://blogs.msdn.com/b/jgoldb/archive/2008/03/08/performant-virtualized-wpf-canvas.aspx