代码之家  ›  专栏  ›  技术社区  ›  Robert Fraser

WPF路径几何更新缓慢_

  •  7
  • Robert Fraser  · 技术社区  · 15 年前

    在WPF用户界面中,节点通过贝塞尔路径连接,如下所示:

    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的解决方案以指数级的速度加快了速度;该函数远未接近瓶颈。有一点反射意味着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 为了好奇。

    3 回复  |  直到 15 年前
        1
  •  7
  •   Mart    15 年前

    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快得多。

    当你为 四象限段 它重新计算一切。这就是为什么速度慢的原因。当它已经添加到几何图形时,速度会更慢。

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

        2
  •  0
  •   Mart    15 年前

    如果不需要点击测试、上下文菜单、曲线工具提示,可以使用简单的视觉效果而不是框架元素。

        3
  •  0
  •   codekaizen    15 年前

    我可以想象,您的性能问题来自 FrameworkElement 并让WPF布局引擎在计算曲线时重新计算布局。

    您可以考虑的是通过从 Freezable 然后使用 框架元素 (如pathgeometry)显示实际的几何图形。