web-dev-qa-db-ja.com

WPFで可能な限り効率的にグラフィックを描画する方法

グラフノードツリーに大きく依存するツールを作成しています。現在の実装はJavaで行われ、C#の汎用コードベースに移植しているので、さまざまなレンダリング実装で使用できます。また、ユーザーフレンドリーなインターフェイスのためのWPF。

1日ブラウジングした後、WPFを介してベクターグラフィックを描画するさまざまな方法に出会いました。

この男 WPF開発者が選択できるさまざまなレイヤーについて話します。最初はWPFPURELYを使ってレンダリングしたいので、「ビジュアルレイヤー」で作業したいと思います。

次に、次のようなものに出くわしました: DrawingVisualGeometryDrawingFrameworkElement / IElement /Shapes

ですから、私は、最終的にはまったく異なる方法で同じことを行うすべての異なる実装に少し圧倒されています。

Graph-Nodeライブラリは、すべてのロジック(衝突検出やマウスでのドラッグを含む)とともにすでにC#に移植されています。グラフィックレンダラー(XNA、SlimDX、OpenTKなど)を念頭に置いて作成されているため、パフォーマンスの観点からWPFレンダラーを実装するための最良の方法は何でしょうか(グラフライブラリが指示するものは何でも描画します)。描く?

基本的に、結果のWPFコントロールはキャンバスとして機能しますが、超軽量で、円、線、その他の形状を描画する方法を提供する以外に、きちんとしたWPF機能を備えていない必要があります:)

編集:

私は基本的に知りたいです:行く方法は何ですか?グラフィックの「ホスト」としてCanvasを拡張してから、UIElementのカスタム実装を追加しますか?または、すべてを描画できるクラスを1つ持つことはできますか(1つのメガスーパーウルトラグラフィックのように)。 GDIのOnPaintまたはJava(すべてを実行するためのGraphicsオブジェクトを提供する)のPaintメソッド)をオーバーライドするのとよく似ています。

20

読むことをお勧めします パフォーマンスの最適化:2Dグラフィックスとイメージング (リンク切れ-インターネットアーカイブ経由で読み取り可能)-

基本的に、Drawingオブジェクトは一般的にShapesよりも軽量になります。これはおそらくあなたが使いたいものです。

12
Reed Copsey

一般に、パフォーマンスは低レベルのサービスで得られます。 WPFでは、これはDrawingファミリーのオブジェクトを意味します。取得できるのは、DrawingDrawingGroupGeometryDrawingGlyphRunDrawingImageDrawing、およびVideoDrawingだけです。ただし、すべてのニーズに十分対応できます。 DrawingはWPFがGPUアクセラレータと交換する概念的な単位であり、可能であればそこで保持および管理するため、これらのタイプの使用はWPFと非常に便利です。これが機能するのは、Drawingがポータブルベクトル描画プリミティブで表現されているためです。

ただし、Drawingsを中心にアプリの再設計を開始すると、UIElementFrameworkElementなどに基づいた高レベルのコードとの相互運用が必要になる場合があります。 WPFに組み込まれていることがわからないのは、図面をFrameworkElementとしてラップするを可能な限りオーバーヘッドの少ない方法で行う簡単な方法です。 DrawingVisualVisualからのみ派生するため、完全なソリューションではありません。つまり、ホスティング要素が必要です。

次のクラスは、中間のDrawingを使用せずに、任意のWPF 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 DrawingInlineUIContainer.Childプロパティに挿入する場合にも役立ちます(つまり、TextBlock.InlinesCollectionを使用してTextBlockのコンテンツをより豊富にフォーマットします)。

6
Glenn Slayden

drawingVisualは有効な選択のようです。

DrawingVisualは、図形、画像、またはテキストをレンダリングするために使用される軽量の描画クラスです。このクラスは、レイアウトやイベント処理を提供せず、パフォーマンスが向上するため、軽量と見なされます。このため、描画は背景やクリップアートに最適です。

ソース: DrawingVisualオブジェクトの使用

だから、これは絶対にあなたが求めるもののようです、CanvasSUPER軽量。

1
Davide Piras