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

时间:2011-09-09 19:33:27

标签: c# wpf graphics graph vector-graphics

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

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

This guy谈论WPF开发人员可以选择的不同层。因为我想首先使用WPF PURELY进行渲染,所以我想开发“Visual Layer”。

然后我遇到了类似的事情: DrawingVisualGeometryDrawingFrameworkElement / UIElement /形状

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

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

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

编辑:

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

3 个答案:

答案 0 :(得分:11)

我建议阅读Optimizing Performance: 2D Graphics and Imaging(死链接 - 通过互联网档案可读) -

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

答案 1 :(得分:5)

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

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

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

Margin

[edit:]这对于将WPF 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(); } }; 插入Drawing属性(即使用InlineUIContainer.Child更丰富地格式化TextBlock的内容)也很有用。

答案 2 :(得分:0)

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

  

DrawingVisual是一个用于的轻量级绘图类   渲染形状,图像或文本。这个类被认为是轻量级的   因为它不提供布局或事件处理,这提高了   它的表现。因此,图纸非常适合背景   和剪贴画。

来源:Using DrawingVisual Objects

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