WPF PathGeometry Update - _SLOW_

In the WPF user interface, I have nodes connected by bezier paths, for example:

It could be ... atomic http://nv3wrg.blu.livefilestore.com/y1pIGBd33lCC6lF-9H0MqgnL40BdNEoEemZDENzgpEI1IL2j4B-qb3qS3WlxMSys28IjqNngR7mdfvQBnPzerf4cJjQjBqQbBQFBQQBBQFBQFBQFBQFBQFBQFBQFBQBBQFBQFBQFBQFBQFBQQBBQPBFQFBQBBQPBFQQBBQPBFQFBQQBBQPBFQFBQQBBQPBFQFBQFBQQBBQPBFQFBQQBURBZBFQQURBK

When a user drags a node object, the connection paths must be updated in real time. However, I noticed some slowdown (especially if one node is connected to many others, or several nodes are dragged immediately). I have profiled it, and the main problem seems to be here:

Evidence. I really used a profiler, so please, not so "OMG", premature opium; you are demon !! "http://nv3wrg.blu.livefilestore.com/y1pjRfQYuN57yei5qdUxW4Dlh4vVCzPy8TcfEzlw_8cUicfOR6BwHCTntcQbQUspRAgBdKcItC0ZcEJbIWMBtKpCrcfcrcfcrcfcrcfcrcfcrtc

This is a function that is called every time a source or target property changes. It seems that the geometry that makes up the path is restored internally every time one of the control points changes. Perhaps if there was a way to prevent the regeneration of geometry until all the relevant dependency properties were set?

EDIT: Mart's decision to use StreamGeometry accelerated it exponentially; the function never comes close to a bottleneck. A little Reflecting assumes that PathGeometry uses StreamGeometry internally, and every time any dependency properties change, StreamGeometry is recalculated. Thus, this method simply cuts off the intermediary. Final result:

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); } } 

The full source code of the project is available at http://zeal.codeplex.com for the curious.

+7
performance c # wpf pathgeometry
source share
3 answers

1- I would try using 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 

It looks much faster than PathGeometry + PathFigure.

When you set Point to QuadraticBezierSegment, it recounts everything. That is why it is slow. And even slower when it is already added to the geometry.

2. Try using only 1 frame element for all of your curves. Check It Out: Writing More Effective Controls

+7
source share

If you don't need kick tests, context menus, tooltips for your curves, you can use simple visual elements instead of structure elements.

0
source share

I would suggest that your performance problems come from decreasing from FrameworkElement , and the WPF layout engine recounts the layout as the curve computes.

What you can consider is to model the curve in descending order from Freezable , and then use a FrameworkElement (e.g. PathGeometry) to display the actual geometry.

0
source share

All Articles