如何在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(它提供了一个图形对象来做任何事情)。

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

我推荐阅读优化性能:2D图形和成像。

一般来说,Drawing的质量会比Shapes轻。

一般情况下,较低级别的服务可以获得较好的性能。在WPF中,这意味着Drawing对象族。所有您得到的是:Drawing, DrawingGroup, GeometryDrawing, GlyphRunDrawing, ImageDrawingVideoDrawing。然而,它们足以满足所有需求。使用这些类型对WPF非常友好,因为Drawing是WPF与GPU加速器交换的概念单元,如果可能的话,可能会保留和管理它。这是因为Drawing是用可移植的矢量绘图原语来表示的。

一旦你开始围绕Drawings重新构建你的应用,你可能需要与你的高级代码进行一些互操作,这些代码仍然基于UIElement, FrameworkElement等。有一件事我没有发现WPF内置的是一种简单的方法,可以以最低开销的方式将绘图包装为FrameworkElementDrawingVisual不是一个完整的解决方案,因为它只派生自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的内容)也很有用。

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

DrawingVisual是一个轻量级绘图类,用于呈现形状、图像或文本。这个类被认为是轻量级的因为它不提供布局或事件处理,这改进了它的性能。因此,图画是理想的背景和剪贴画。

来源:Using DrawingVisual Objects

所以这似乎绝对是你想要的,一个Canvas超轻量级