7

WPF UIには、次のようにベジェパスで接続されたノードがあります。

それは...アトミックhttp://nv3wrg.blu.livefilestore.com/y1pIGBd33lCC6lF-9H0MqgnL40BdNEoEemZDENzgpEI1IL2j4B-qb3qS3WlxMSys28IjqNngR7mdfvQBnPzerf4cFJQj9VqHB

ユーザーがノードをドラッグするときは、接続パスをリアルタイムで更新する必要があります。ただし、速度が低下していることに気づきました(特に、1つのノードが他の多くのノードに接続されている場合、または複数のノードが同時にドラッグされている場合)。私はそれをプロファイリングしました、そして主な問題はここにあるようです:

証明私は実際にプロファイラーを使用したので、「OMG、時期尚早のopiumzation、あなたは悪魔です!!」のようになってはいけません。http://nv3wrg.blu.livefilestore.com/y1pjRfQYuN57yei5qdUxW4Dlh4vVCzPy8TcfEzlw_8cUicfOR6BwHCTntcQbQUspRAgBdKcItC0ZcEJbIWMKaYrCtDMOtCB

これは、ソースプロパティまたは宛先プロパティのいずれかが変更されるたびに呼び出される関数です。パスを構成するジオメトリは、コントロールポイントが変更されるたびに内部で再生成されているようです。おそらく、関連するすべての依存関係プロパティが設定されるまで、ジオメトリが再生成されないようにする方法があったとしたらどうでしょうか。

編集: StreamGeometryを使用するMartのソリューションは、指数関数的に高速化しました。この機能はボトルネックにはほど遠いです。少し反映すると、PathGeometryは内部でStreamGeometryを使用し、依存関係のプロパティが変更されるたびに、StreamGeometryが再計算されます。したがって、この方法では仲介者を切り取るだけです。最終結果は次のとおりです。

private void onRouteChanged()
{
    Point src = Source;
    Point dst = Destination;
    if (!src.X.isValid() || !src.Y.isValid() || !dst.X.isValid() || !dst.Y.isValid())
    {
        _shouldDraw = false;
        return;
    }

    /*
        * The control points are all laid out along midpoint lines, something like this:
        * 
        *   -------------------------------- 
        *  |          |          |          |
        *  |   SRC    |    CP1   |          |
        *  |          |          |          |
        *   -------------------------------- 
        *  |          |          |          |
        *  |          |    MID   |          |
        *  |          |          |          |
        *   ------------------------------- 
        *  |          |          |          |
        *  |          |    CP2   |    DST   |
        *  |          |          |          |
        *   -------------------------------- 
        *   
        * This causes it to be horizontal at the endpoints and vertical
        * at the midpoint.
        */

    double mx = (src.X + dst.X) / 2;
    double my = (src.Y + dst.Y) / 2;
    Point mid = new Point(mx, my);
    Point cp1 = new Point(mx, src.Y);
    Point cp2 = new Point(mx, dst.Y);

    _geometry.Clear();
    _shouldDraw = true;
    using(StreamGeometryContext ctx = _geometry.Open())
    {
        ctx.BeginFigure(src, false, false);
        ctx.QuadraticBezierTo(cp1, mid, true, false);
        ctx.QuadraticBezierTo(cp2, dst, true, false);
    }
}

プロジェクトの完全なソースコードは、http://zeal.codeplex.comで入手できます。

4

3 に答える 3

7

1- StreamGeometryを使用しようとします:

        StreamGeometry streamGeo = new StreamGeometry();
        Stopwatch sw = new Stopwatch();
        sw.Start();
        for (int i = 0; i < 10000; i++)
        {
            streamGeo.Clear();
            var ctx = streamGeo.Open();
            ctx.BeginFigure(new Point(0, 0), false, false);
            ctx.QuadraticBezierTo(new Point(10, 10), new Point(10, i), true, true);
            ctx.Close();
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds); // For 10k it took 30 ms

PathGeometry+PathFigureよりもはるかに高速に見えます。

QuadraticBezierSegmentのポイントを設定すると、すべてが再計算されます。それが遅い理由です。そして、それがすでにジオメトリに追加されている場合は、より遅くなります。

2-すべての曲線に1つのframeworkelementのみを使用するようにしてください。これをチェックしてください: より効率的なItemsControlsを書く

于 2010-07-07T07:03:36.960 に答える
0

ヒットテスト、コンテキストメニュー、曲線のツールチップが必要ない場合は、フレームワーク要素の代わりに単純なビジュアルを使用できます。

于 2010-07-07T06:00:17.137 に答える
0

FrameworkElementパフォーマンスの問題は、曲線の計算時にWPFレイアウトエンジンにレイアウトを再計算させることから生じると思います。

Freezable考慮できるのは、FrameworkElement(PathGeometryのように)から降りて曲線をモデル化し、実際のジオメトリを表示することです。

于 2010-07-07T07:03:43.260 に答える