如何提高Canvas渲染性能?

时间:2012-04-03 16:56:40

标签: wpf performance canvas rendering shape

我必须画出很多Shape(约半十万)作为[Canvas] [2]的孩子们。我在我的WPF应用程序中将这项工作分为两部分:首先,我通过设置每个属性(如边距,填充,宽度等等)来创建形状,然后我将形状添加为Canvas的子项。

MyCanvas.Children.Add(MyShape)

现在我想提高第二部分的性能,因为当我绘制形状时,我的应用程序被封锁了很长一段时间。所以我尝试使用Dispatcher及其方法[BeginInvoke] [4]和不同的[优先级] [5]:只有当我使用后台优先级时,主应用程序才会阻止,否则应用程序将被阻止,直到所有形状都添加到我的画布中才会显示“图片”,但如果我使用背景优先级,显然一切都会变慢。我也尝试创建一个新线程,而不是使用Dispatcher,但没有重大改变。

如何解决此问题,并在将形状添加到Canvas时通常可以提高应用程序的性能?

感谢。

4 个答案:

答案 0 :(得分:7)

需要使用Visual个对象而不是Shape;特别是,如建议的那样,DrawingVisual:可用于渲染矢量图形的可视对象。实际上,正如MSDN库中所写:

  

DrawingVisual是一个轻量级绘图类,用于渲染形状,图像或文本。此类被视为轻量级,因为它不提供布局,输入,焦点或事件处理,从而提高了性能。因此,图纸非常适合背景和剪贴画。

因此,例如,创建一个包含矩形的DrawingVisual:

private DrawingVisual CreateDrawingVisualRectangle()
{
   DrawingVisual drawingVisual = new DrawingVisual();

   // Retrieve the DrawingContext in order to create new drawing content.
   DrawingContext drawingContext = drawingVisual.RenderOpen();

   // Create a rectangle and draw it in the DrawingContext.
   Rect rect = new Rect(new System.Windows.Point(160, 100), new System.Windows.Size(320, 80));
   drawingContext.DrawRectangle(System.Windows.Media.Brushes.LightBlue, (System.Windows.Media.Pen)null, rect);

   // Persist the drawing content.
   drawingContext.Close();

   return drawingVisual;
}

要使用DrawingVisual对象,您需要为对象创建主机容器。主机容器对象必须派生自FrameworkElement类,该类提供DrawingVisual类缺少的布局和事件处理支持。为可视对象创建主机容器对象时,需要将可视对象引用存储在VisualCollection中。

public class MyVisualHost : FrameworkElement
{
   // Create a collection of child visual objects.
   private VisualCollection _children;

   public MyVisualHost()
   {
       _children = new VisualCollection(this);
       _children.Add(CreateDrawingVisualRectangle());

       // Add the event handler for MouseLeftButtonUp.
       this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(MyVisualHost_MouseLeftButtonUp);
   }
}

然后,事件处理例程可以通过调用HitTest方法来实现命中测试。方法的HitTestResultCallback参数引用用户定义的过程,您可以使用该过程来确定命中测试的结果操作。

答案 1 :(得分:3)

同意如果你想绘制数百万个元素,你根本无法在WPF中完成。如上所述,WriteableBitmapEx是一个不错的选择。

请参阅this related question,其中介绍了WPF中的高性能图形以及可用的替代方案。

如果您只是必须使用Canvas,请查看此ZoomableApplication2 - A million items。这是一个基于Canvas的演示,它大量使用Virtualization来在Canvas上获得1,000,000个UIElements的合理性能。

答案 2 :(得分:1)

这是很多的UIElements,可能不会给你正在寻找的那种性能。您是否需要能够与正在渲染的每个元素进行交互?如果没有,我强烈建议您考虑使用WriteableBitmap。如果您需要绘制形状而不想自己创建所有逻辑(谁想要?),check out the WriteableBitmapEx project over on CodePlex

答案 3 :(得分:1)

这可能有些不相关,如果您有这种感觉我会道歉,但希望它可以为其他用户提供一些亮点,我会分享这个消息。

我们在使用用于捕获签名的Canvas控件时遇到了一些性能问题。捕获非常锯齿状,因此我们无法绘制曲线。事实证明,风格与UI元素产生阴影有关。禁用阴影效果解决了我们的问题。