如何在WPF中尽可能高效地绘制图形
本文关键字:高效 绘制 图形 尽可能 WPF | 更新日期: 2023-09-27 18:08:14
我正在创建一个严重依赖图节点树的工具。目前的实现是在Java中完成的,我正在将它移植到c#的通用代码库中,这样它就可以被各种渲染实现使用,也因为我想利用WPF的强大功能来创建一个用户友好的界面。
在浏览了一天之后,我发现了用WPF绘制矢量图形的各种方法。
这家伙谈到了WPF开发人员可以选择的不同层。因为我一开始想用WPF纯渲染,所以我想在"视觉层"上工作。
然后我遇到了这样的东西:DrawingVisual,GeometryDrawing,FrameworkElement/UIElement/Shapes
所以,我对所有不同的实现有点不知所措,它们最终以完全不同的方式做同样的事情。
Graph-Node库已经被移植到c#了,它的所有逻辑(包括碰撞检测和鼠标拖动)。因为它是用图形渲染器(如XNA, SlimDX, OpenTK等)制作的,在性能方面实现WPF渲染器的最佳方式是什么(例如,它将绘制图形库告诉它绘制的任何内容)?
基本上,生成的WPF控件充当画布,但它必须是超轻量级的,除了提供我绘制圆圈,线条和其他形状的方法之外,没有任何整洁的WPF功能:)
编辑:我基本上想知道:该怎么走?我扩展画布作为"主机"为我的图形,然后添加我的自定义实现的UIElement?或者我可以有一个类,可以画一切(如,一个超级超级图形)。很像重写GDI中的OnPaint或Java中的Paint-method(它提供了一个图形对象来做任何事情)。
我推荐阅读优化性能:2D图形和成像。
一般来说,Drawing
的质量会比Shapes
轻。
一般情况下,较低级别的服务可以获得较好的性能。在WPF
中,这意味着Drawing
对象族。所有您得到的是:Drawing
, DrawingGroup
, GeometryDrawing
, GlyphRunDrawing
, ImageDrawing
和VideoDrawing
。然而,它们足以满足所有需求。使用这些类型对WPF非常友好,因为Drawing
是WPF与GPU加速器交换的概念单元,如果可能的话,可能会保留和管理它。这是因为Drawing
是用可移植的矢量绘图原语来表示的。
一旦你开始围绕Drawings
重新构建你的应用,你可能需要与你的高级代码进行一些互操作,这些代码仍然基于UIElement
, FrameworkElement
等。有一件事我没有发现WPF内置的是一种简单的方法,可以以最低开销的方式将绘图包装为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的内容)也很有用。
DrawingVisual似乎是一个有效的选择:
DrawingVisual是一个轻量级绘图类,用于呈现形状、图像或文本。这个类被认为是轻量级的因为它不提供布局或事件处理,这改进了它的性能。因此,图画是理想的背景和剪贴画。
来源:Using DrawingVisual Objects
所以这似乎绝对是你想要的,一个Canvas超轻量级