簡體   English   中英

如何在 WPF 中盡可能高效地繪制圖形

[英]How to draw graphics as efficiently as possible in WPF

我正在創建一個嚴重依賴圖節點樹的工具。 當前的實現是用 Java 完成的,我將它移植到基於 C# 的通用代碼庫,因此它可以被各種渲染實現使用,也因為我想使用 WPF 的強大功能來實現用戶友好的界面。

瀏覽了一天后,我遇到了各種通過 WPF 繪制矢量圖形的方法。

這家伙談到了 WPF 開發人員可以選擇的不同層。 因為我想首先使用 WPF PURELY 進行渲染,所以我想在“視覺層”上工作。

然后我遇到了這樣的事情: DrawingVisualGeometryDrawingFrameworkElement / UIElement / Shapes

因此,我對所有最終以完全不同的方式執行相同操作的不同實現感到有些不知所措。

Graph-Node 庫已經連同它的所有邏輯(包括碰撞檢測和鼠標拖動)移植到 C# 中。 因為它是在考慮圖形渲染器(如 XNA、SlimDX、OpenTK 等)的情況下制作的,所以在性能方面實現 WPF 渲染器的最佳方式是什么(例如,它將繪制圖形庫告訴它的任何內容)畫畫?

基本上,生成的 WPF 控件充當畫布,但它必須是超級輕量級​​的,除了為我提供繪制圓圈、線條和其他形狀的方法之外,沒有任何簡潔的 WPF 功能:)

編輯:

我基本上想知道:要走什么路? 我是否將 Canvas 擴展為我的圖形的“宿主”,然后添加我對 UIElement 的自定義實現? 或者我可以有一個可以繪制所有東西的類(例如,一個超級超級圖形)。 很像在 GDI 中覆蓋 OnPaint 或在 Java 中覆蓋 Paint-method(它提供一個 Graphics 對象來做所有事情)。

我建議閱讀Optimizing Performance: 2D Graphics and Imaging

基本上, Drawing對象通常比Shapes更輕。 這可能是您想要使用的。

通常,使用較低級別的服務可以獲得更好的性能。 WPF ,這意味着對象的Drawing系列。 你得到的只有: DrawingDrawingGroupGeometryDrawingGlyphRunDrawingImageDrawingVideoDrawing 但是,它們足以滿足所有需求。 使用這些類型對 WPF 非常友好,因為Drawing是 WPF 與 GPU 加速器交換的概念單元,如果可能,可能會在那里保留和管理它。 這是有效的,因為Drawing是根據可移植的矢量繪圖基元來表達的。

但是,一旦您開始圍繞Drawings重新構建您的應用程序,您可能需要與仍然基於UIElementFrameworkElement等的更高級別代碼進行一些互操作。我還沒有發現 WPF 內置的一件事是一個簡單的以盡可能低的開銷方式將繪圖包裝為 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();
    }
};

[編輯:] 這對於將 WPF Drawing插入InlineUIContainer.Child屬性也很有用(即使用 TextBlock.InlinesCollection 更豐富地格式化TextBlock.InlinesCollection的內容)。

DrawingVisual 似乎是一個有效的選擇:

DrawingVisual 是一個輕量級的繪圖類,用於呈現形狀、圖像或文本。 此類被認為是輕量級的,因為它不提供布局或事件處理,從而提高了其性能。 因此,繪圖是背景和剪貼畫的理想選擇。

來源:使用 DrawingVisual 對象

所以這似乎絕對是你要問的,Canvas SUPER 輕量級。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM