【发布时间】:2014-09-14 21:12:33
【问题描述】:
我有多达 70000 个形状派生对象要添加到画布中。显然这会导致 UI 无响应,在我的情况下大约 20 秒。我已经尝试使用 Dispatcher 方法来尝试克服这个问题,但我仍然遇到问题。
我实现它的第一种方式是这样的:
foreach (var shape in ShapeList)
{
Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
drawingCanvas.Children.Add(shape);
}));
}
这确实使 UI 具有响应性,但不利的一面是,它需要很长时间(比如 10 分钟?)才能完全添加所有形状。它还会在添加形状时立即显示形状。
我实现它的第二种方式是:
Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
foreach (var shape in ShapeList)
{
drawingCanvas.Children.Add(shape);
}
}));
这似乎与根本不使用调度程序具有相同的效果。
我已经在单独的线程上尝试了这两种实现,并且与主线程没有区别。此外,我必须将它们全部添加为单独的 Shape 对象,因为它们中的每一个都必须支持单独的 MouseClickEvents,因此我没有使用 drawingVisual。
那么有什么方法可以让主窗口保持响应,同时保持添加过程相对较快?
谢谢。
*编辑 我知道 CanvasVirtualization 但目前我理解起来似乎有点复杂。有没有其他方法可以使用?
【问题讨论】:
-
70,000 是放在 Canvas 对象上的很多东西。如果这些对象是只读的/非交互的,你会考虑使用类似 WriteableBitmap 的东西吗?
-
Adding them on another thread 听起来是个好主意,我无法让它发挥作用,也许你可以。
-
我遇到了同样的问题。您使用 Dispatcher 的方法是正确的,也是唯一的方法,因为您必须在 UI 线程上创建 UI 元素。恐怕对于这么多的对象,您将不得不使用画布虚拟化。但是,对我有用的方法是使用 ItemsControl 为 Canvas 定义模板,并用视图模型表示我的形状,我将其放入集合中并绑定到 ItemsControl。然后我使用模板来定义形状的外观。我不知道为什么,但是这种方法给了我比向 Canvas.Children 添加项目更好的性能。如果您想尝试,我可以发布代码。
-
@McGarnagle:所有对象都是交互式的。它们都可以被选中并附加一个 mousebuttondown 事件处理程序。在这种情况下是否仍然可以使用可写位图?
-
我猜不是,如果它们是交互式的。而且我想我可能是错的,70,000 并不是所有那么多...但我仍然认为您最终可能不得不进行某种优化,例如虚拟画布...
标签: c# wpf performance user-interface wpf-controls