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.