如何在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
对象系列。 所有你得到的是: Drawing
, DrawingGroup
, GeometryDrawing
, GlyphRunDrawing
, ImageDrawing
和VideoDrawing
。 但是,它们足以满足所有需求。 使用这些类型对WPF非常友好,因为Drawing
是WPF与GPU加速器交换的概念单元,如果可能的话可能会在那里保留和管理它。 这是有效的,因为Drawing
是用便携式矢量绘图原语表示的。
然而,一旦你开始围绕Drawings
重新构建你的应用程序,你可能需要与你的更高级代码进行一些互操作,这仍然基于UIElement
, FrameworkElement
等。我没有找到WPF内置的一件事很简单以尽可能低的开销方式将Drawing包装为FrameworkElement的方法。 DrawingVisual
不是一个完整的解决方案,因为它只源于Visual
意味着它仍然需要托管元素。
以下类将直接托管任何WPF Drawing
,而不使用中间的DrawingVisual
。 我添加了对FrameworkElement
的Margin
属性的支持(如果未使用则不会造成性能损失),但很少。 由于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轻量级。