如何在WPF中尽可能高效地绘制图形

我正在创建一个严重依赖图节点树的工具。 当前的实现是用Java完成的,我将它移植到C#上的通用代码库中,因此它可以被各种渲染实现使用,也因为我想使用WPF的强大function来实现用户友好的界面。

浏览了一天之后,我遇到了各种方法来通过WPF绘制矢量图形。

这个人讲的是WPF开发人员可以选择的不同层。 因为我想首先使用WPF PURELY进行渲染,所以我希望使用“Visual Layer”。

然后我遇到了类似的东西: DrawingVisual , GeometryDrawing , FrameworkElement / UIElement / Shapes

所以,我对所有不同的实现有点不知所措,这些实现最终以完全不同的方式完成相同的操作。

Graph-Node库已经用它的所有逻辑(包括碰撞检测和用鼠标拖动)移植到C#。 因为它是用图形渲染器(如XNA,SlimDX,OpenTK等)制作的,所以在性能方面实现WPF渲染器的最佳方式(如同,它将绘制图形库告诉它的任何东西)画画?

基本上,生成的WPF控件充当canvas,但它必须是SUPER轻量级,除了为我提供绘制圆圈,线条和其他形状的方法之外,没有任何简洁的WPFfunction:)

编辑:

我基本上想知道:要走的路是什么? 我是否将Canvas扩展为我的图形的“主机”,然后添加我的UIElement的自定义实现? 或者我可以拥有一个可以绘制一切的课程(例如,一个超级超级超级图形)。 就像重写GDI中的OnPaint或Java中的Paint-method(它为Graphics对象提供所有function)。

我建议阅读优化性能:2D图形和成像 (死链接 – 可通过Internet Archive读取) –

基本上, Drawing对象通常比Shapes更轻。 这可能是你想要使用的。

通常,使用较低级别的服务可以获得更好的性能。 在WPF ,这意味着Drawing对象系列。 所有你得到的是: DrawingDrawingGroupGeometryDrawingGlyphRunDrawingImageDrawingVideoDrawing 。 但是,它们足以满足所有需求。 使用这些类型对WPF非常友好,因为Drawing是WPF与GPU加速器交换的概念单元,如果可能的话可能会在那里保留和管理它。 这是有效的,因为Drawing是用便携式矢量绘图原语表示的。

然而,一旦你开始围绕Drawings重新构建你的应用程序,你可能需要与你的更高级代码进行一些互操作,这仍然基于UIElementFrameworkElement等。我没有找到WPF内置的一件事很简单以尽可能低的开销方式将Drawing包装为FrameworkElement的方法。 DrawingVisual不是一个完整的解决方案,因为它只源于Visual意味着它仍然需要托管元素。

以下类将直接托管任何WPF Drawing ,而不使用中间的DrawingVisual 。 我添加了对FrameworkElementMargin属性的支持(如果未使用则不会造成性能损失),但很少。 由于WPF的单个渲染线程,缓存单个TranslateTransform对象以实现边距是安全且容易的。 我建议您只提供已冻结的图纸; 事实上,在我使用的版本中,我在构造函数中有一个断言。

 public class DrawingElement : FrameworkElement { static readonly TranslateTransform tt_cache = new TranslateTransform(); public DrawingElement(Drawing drawing) { this.drawing = drawing; } readonly Drawing drawing; TranslateTransform get_transform() { if (Margin.Left == 0 && Margin.Top == 0) return null; tt_cache.X = Margin.Left; tt_cache.Y = Margin.Top; return tt_cache; } protected override Size MeasureOverride(Size _) { var sz = drawing.Bounds.Size; return new Size { Width = sz.Width + Margin.Left + Margin.Right, Height = sz.Height + Margin.Top + Margin.Bottom, }; } protected override void OnRender(DrawingContext dc) { var tt = get_transform(); if (tt != null) dc.PushTransform(tt); dc.DrawDrawing(drawing); if (tt != null) dc.Pop(); } }; 

[edit:]这对于将WPF Drawing插入InlineUIContainer.Child属性(即使用TextBlock.InlinesCollection来更丰富地格式化TextBlock.InlinesCollection的内容)也很有用。

DrawingVisual似乎是一个有效的选择:

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

source: 使用DrawingVisual对象

所以这似乎绝对是你要求的,Canvas SUPER轻量级。