在WPF UI中,我有通过贝塞尔曲线路径连接的节点,如下所示:

It might be... atomic http://nv3wrg.blu.livefilestore.com/y1pIGBd33lCC6lF-9H0MqgnL40BdNEoEemZDENzgpEI1IL2j4B-qb3qS3WlxMSys28IjqNngR7mdfvQBnPzerf4cFJQj9VqHBh4/acurve.png?psid=1

当用户在周围拖动节点时,需要实时更新连接路径。但是,我注意到速度有所下降(特别是如果一个节点连接到许多其他节点,或者一次拖动多个节点)。我分析了它,主要问题似乎在这里:

Proof I actually used a profiler, so please don't be all like "OMG, premature opiumzation; you are DEMON!!" http://nv3wrg.blu.livefilestore.com/y1pjRfQYuN57yei5qdUxW4Dlh4vVCzPy8TcfEzlw_8cUicfOR6BwHCTntcQbQUspRAgBdKcItC0ZcEJbIWMKaYrCtDMOtCBKB4g/profile.png?psid=1

每次更改源或目标属性时都会调用此函数。每次更改任何控制点时,似乎都会在内部重新生成构成路径的几何图形。也许是否有一种方法可以防止在所有相关的依赖属性都设置好之后重新生成几何图形?

编辑: Mart使用StreamGeometry的解决方案以指数方式加快了速度;该功能远非瓶颈。稍微的反射(reflect)表明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上获得该项目的完整源代码。

最佳答案

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设置Point时,它将重新计算所有内容。这就是为什么它很慢。当它已经添加到几何图形时,速度会变慢。

2-尝试对所有曲线仅使用1个Frameworkelement。检查一下:
Writing More Efficient ItemsControls

10-04 18:53