I’m trying to do a manual undo implementation for moving nodes and manually applying layouts. It seems like I’d want to capture each Node.Position value from the Diagram and then later call Node.Move() with that saved position. (My goal here is that I’d get a nice animated move versus doing it in the model which would just jump the nodes to their new positions.) Assuming that’s correct, do I need to do anything to the attached Link objects to get them to recalculate their routes? Do I just call Link.Remeasure() on each impacted link or does Node.Move() already account for that? Or do I need to do something more subtle with the Relinking or LinkReshaping tool?
I assume you’re trying to animate undo and redo to get effects just like the standard layout animation.
No, you don’t need to do anything besides call Node.Move – connected links and containing groups get updated automatically. However, such re-routing of connected links means that you will lose any undo or redo of changes to those link routes. This might not be an issue for your app. But it required non-trivial programming to get the right results for layout animation, and those built-in smarts won’t help you with your kind of animation.
You’re correct that losing the undo/redo changes when the links are re-routed is not an issue for my app. However, I’m now running into a different issue: I have undo/redo buttons in my application. Clicking one of them invokes the appropriate command and the nodes have a nice animated movement into their desired position. However, if I mash one of these buttons repeatedly (thereby applying multiple undos in quick succession, for example), I do not end up with the correct layout. (The multiple button presses occur before the first layout animation has completed.) When the nodes finish moving, they’re at the location I’d expect after the first button press (rather than the last button press).
How can I solve this problem? I didn’t see anything on the Node or Diagram classes that indicated an animated layout operation was in effect. I considered possibly wrapping all of this in a derivation of DiagramLayout, but I didn’t see anything on the LayoutManager that indicated an animated operation was currently in effect. The only solution which I could come up with is start a timer with the same duration as LayoutManager.AnimationTime and then disable my undo/redo buttons until the timer ticked. I think that’s a terrible solution and I’m hoping you can provide a better one.
And I’m not sure if it matters, but both Model.UndoManager and Diagram.Layout are null. (I’m manually creating a layout, applying it, and then setting Diagram.Layout to null when it completes. I don’t want automatic layouts at this time.)
Actually, there is a LayoutManager.IsAnimating property and even a DiagramPanel.AnimatingChanged event, but both are internal, so officially you can’t use them.
Maybe you could use the Diagram.LayoutCompleted event??? Just speculating…
I don’t think the LayoutCompleted event meets my needs: I need something that tells me an animation or layout is currently in progress thus indicating I should wait until it completes. That event fulfills the completed part of the problem, but not the “something else is in progress” part of the problem.
Well, presumably you know whenever you start making calls to Node.Move for animation.
Sorry, I don’t understand your response. I do know that I’m making calls to Node.Move, but I don’t know if an animation is in progress or not. The LayoutCompleted event tells me (among other things) that an animation has completed, but there’s no way to tell that a layout is in progress (at least as far as I can see).
For the start, you could override LayoutManager.PerformLayout.
This assumes you are not explicitly calling DiagramLayout.DoLayout().
So you’re saying:
- Create a new layout by deriving from DiagramLayout and do all of my node moving inside of that class.
- Create a custom layout manager that derives from LayoutManager, override PerformLayout to indicate a layout is in progress/has completed.
That seems like it would work.
I was only suggesting #2.
Alright, I’m confused again: how does a custom layout manager help this situation? If I call Node.Move(), does the layout manager somehow come into play?
The LayoutManager is what implements/manages/coordinates animated node movement.
It isn’t necessary, but it would be more efficient if you let the LayoutManager coordinate all of the animated node movements.
To explain what I said earlier, if you are calling Node.Move or LayoutManager.MoveAnimated outside of a diagram layout, then you know when you do so, so you know when the animation is starting.
If you define your own layout and use it as the Diagram.Layout, then you can override LayoutManager.PerformLayout, because it will be called when the layout happens, which is just before the layout animation starts.