如何提高Canvas渲染性能?

时间:2022-02-04 01:14:28

I have to draw a lot of Shape (about 1/2 hundred thousand) as [Canvas][2]'s childrens. I make this in my WPF application dividing work in two parts: first thing I create shapes by setting the properties of each of them (like Margin, Fill, Width, etc...), after I add shapes as Canvas's children.

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

MyCanvas.Children.Add(MyShape)

Now i want to improve the performance of the second part, because when i draw the shapes my application is blocked for a long period of time. So i tried to use the Dispatcher and its method [BeginInvoke][4] with different [priorities][5]: only if I use the Background priority the main application does not block, otherwise the application remains blocked and the "picture" is not displayed until all shapes are added to my Canvas, but if I use the Background priority obviously everything is slower. I also tried to create a new thread instead of using the Dispatcher, but there was no significant change.

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

How can I fix this problem, and generally improve the performance of my application when I add my shapes to Canvas?

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

Thanks.

谢谢。

4 个解决方案

#1


7  

Need to use Visual objects instead of Shape; in particular, as suggested, DrawingVisual: a visual object that can be used to render vector graphics. In fact, as written in the MSDN library:

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

DrawingVisual is a lightweight drawing class that is used to render shapes, images, or text. This class is considered lightweight because it does not provide layout, input, focus, or event handling, which improves its performance. For this reason, drawings are ideal for backgrounds and clip art.

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

So, for example, to create a DrawingVisual that contains a rectangle:

因此,例如,要创建包含矩形的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;
}

In order to use DrawingVisual objects, you need to create a host container for the objects. The host container object must derive from the FrameworkElement class, which provides the layout and event handling support that the DrawingVisual class lacks. When you create a host container object for visual objects, you need to store the visual object references in a VisualCollection.

要使用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);
   }
}

The event handling routine can then implement hit testing by invoking the HitTest method. The method's HitTestResultCallback parameter refers to a user-defined procedure that you can use to determine the resulting action of a hit test.

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

#2


3  

Agreed that if you want to draw millions of elements, you simply can't do it in WPF. WriteableBitmapEx as mentioned is a good alternative.

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

See this related question which goes into depth on high performance graphics in WPF and the alternatives available.

请参阅此相关问题,该问题深入介绍了WPF中的高性能图形以及可用的替代方案。

If you simply must use Canvas, check out this ZoomableApplication2 - A million items. This is a Canvas based demo which makes heavy use of Virtualization to get reasonable performance with 1,000,000 UIElements on a Canvas.

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

#3


1  

That's a lot of UIElements and probably isn't going to give the kind of performance you're looking for. Do you need to be able to interact with each of the elements you're rendering? If not, I would highly recommend looking into using WriteableBitmap instead. If you need to draw shapes and don't want to create all that logic yourself (who would want to?), check out the WriteableBitmapEx project over on CodePlex.

这是很多UIElements,可能不会给你正在寻找的那种性能。您是否需要能够与正在渲染的每个元素进行交互?如果没有,我强烈建议改为使用WriteableBitmap。如果你需要绘制形状并且不想自己创建所有逻辑(谁想要?),请在CodePlex上查看WriteableBitmapEx项目。

#4


1  

This may be somewhat unrelated, and I apologize if you feel this way, but in the hopes that it can shed some light for other users, I'll share this tidbit.

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

We had some performance issues with a Canvas control used for capturing signatures. The capture was very jagged, and we couldn't draw curved lines as a result. It turned out to be related to a style was was generating drop-shadows on the UI elements. Disabling the drop-shadow effect solved our problem.

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

#1


7  

Need to use Visual objects instead of Shape; in particular, as suggested, DrawingVisual: a visual object that can be used to render vector graphics. In fact, as written in the MSDN library:

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

DrawingVisual is a lightweight drawing class that is used to render shapes, images, or text. This class is considered lightweight because it does not provide layout, input, focus, or event handling, which improves its performance. For this reason, drawings are ideal for backgrounds and clip art.

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

So, for example, to create a DrawingVisual that contains a rectangle:

因此,例如,要创建包含矩形的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;
}

In order to use DrawingVisual objects, you need to create a host container for the objects. The host container object must derive from the FrameworkElement class, which provides the layout and event handling support that the DrawingVisual class lacks. When you create a host container object for visual objects, you need to store the visual object references in a VisualCollection.

要使用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);
   }
}

The event handling routine can then implement hit testing by invoking the HitTest method. The method's HitTestResultCallback parameter refers to a user-defined procedure that you can use to determine the resulting action of a hit test.

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

#2


3  

Agreed that if you want to draw millions of elements, you simply can't do it in WPF. WriteableBitmapEx as mentioned is a good alternative.

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

See this related question which goes into depth on high performance graphics in WPF and the alternatives available.

请参阅此相关问题,该问题深入介绍了WPF中的高性能图形以及可用的替代方案。

If you simply must use Canvas, check out this ZoomableApplication2 - A million items. This is a Canvas based demo which makes heavy use of Virtualization to get reasonable performance with 1,000,000 UIElements on a Canvas.

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

#3


1  

That's a lot of UIElements and probably isn't going to give the kind of performance you're looking for. Do you need to be able to interact with each of the elements you're rendering? If not, I would highly recommend looking into using WriteableBitmap instead. If you need to draw shapes and don't want to create all that logic yourself (who would want to?), check out the WriteableBitmapEx project over on CodePlex.

这是很多UIElements,可能不会给你正在寻找的那种性能。您是否需要能够与正在渲染的每个元素进行交互?如果没有,我强烈建议改为使用WriteableBitmap。如果你需要绘制形状并且不想自己创建所有逻辑(谁想要?),请在CodePlex上查看WriteableBitmapEx项目。

#4


1  

This may be somewhat unrelated, and I apologize if you feel this way, but in the hopes that it can shed some light for other users, I'll share this tidbit.

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

We had some performance issues with a Canvas control used for capturing signatures. The capture was very jagged, and we couldn't draw curved lines as a result. It turned out to be related to a style was was generating drop-shadows on the UI elements. Disabling the drop-shadow effect solved our problem.

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