This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
Hi, I am struggling with maintaining a clean diagram layout when adding and removing nodes from my diagram. I am using the TreeLayoutAlgorithm which gives me approximately what I want.
Side Issue: I'm not sure what the Info property is supposed to do, so I'm not sure if I should specify something for that or not. The first problem starts when I start adding nodes dynamically. This is done through the code, where a node is added to the diagram and then I programmatically connect them. After the node is added I call ApplyLayoutAlgorithm. As you can see in the image below the new node is sort of in the right place, but the connection starts from the centre of the parent node rather than the edge. This always happens to the parent node. The connection points are always added at the centre, whereas the endpoints are added at the left edge. Another side issue is that for the very first node the connection lines are drawn on top of the node, but for all the others they are drawn underneath. I have a custom Node class which manages the connection points. When Nodes are added in this way the start and end connection points are automatically added to the node to ensure that there are enough connection points to handle the connection. The connection points are added this way: For the parent (or source) node.
For the child (or target) node.
Secondly, why does the new node always appear above its siblings? It's kind of strange, but in some cases it actually causes a problem. In the image below if we try to add a new child to the 'Parent' node, it will appear right on top of the mess of connectors that lead to the first child, and none of the other nodes will adjust accordingly. A third problem I have is that when we are relying on the auto layout, it does not seem to take into account the size of the node itself. Ahh.. That might actually explain my first problem now that I think about it. Perhaps it thinks that is the right edge of my node - based on the default size of a node. Interesting. Anyway, If at some point I ever get around to auto-sizing my nodes to their contents, I'm going to be in big trouble because then there is no way the spacing settings in the TreeLayoutAlgorithm are going to work properly. Any suggestions? |
|
|
Is there an example using ms:DiagramNodeElement.RaisesBoundsChangeRequested="True" anywhere? I've looked in all the samples and I can't find any. |
|
|
Hello Eliz You won't need to worry about the Info property. This is just to tell the layout algorithm that certain types of nodes should be ignored (e.g. title and comment nodes). For your first issue, If you manually resize the node, does the connection point still align itself to the center of the node, or does it stay at the exact same diagram coordinate, or does it snap to the right edge? I have not been able to reproduce this issue, so my only guess is that some point in code is inadvertently specifying that the outbound connections, or maybe the right-edge connections should be positioned at the center. If you can send a repro project, I'll be able to solve the problem for you. Also, you should be able to control the relative layers of each element by setting the ZOrder property of each node and connection when you are adding them. When the tree layout is set to top-to-bottom, the child nodes are positioned from left to right in the order they are added to the diagram. In left-to-right layout, the algorithm simply rotates this pattern, and so the children end up being positioned from bottom to top in the order they are added. You should be able to change this by inserting each new child node before any of its sibling nodes within the Nodes collection. Also, keep in mind that the layout algorithms don't take the connections into consideration. To avoid connection overlaps, you'd need to use the AStarPathfinder. Auto sizing the nodes to their contents will update their Bounds properties. This is used by the layout algorithms, so it shouldn't be a problem. The support for auto sizing nodes is currently not that great though. Let me know if you run into problems here. We do not have any samples for RaiseBoundsChangeRequested as it was an experimental feature. Feel free to use it though as it may suit your needs. To use, set DiagramNodeElement.RaiseBoundsChangeRequested to true on an element within your node template that is going to be the source of the node sizing. A TextBlock for example. Then in code, attach an event handler to the DiagramSurface to listen to the DiagramNodeElement.BoundsChangeRequestedEvent.
Then in the event handler, you'll get the width and height of the element that you set the attached property, as well as the element itself. Then you can use these values to determine the new size that you want for the node, and then set the bounds of the node of the DiagramNodeElement - also available in the event args. You probably simply want to add some margin to the width and height. Let me know if you have questions about any of this. -Jason Fauchelle |
|
|
Thanks for the info! I have progressed quite a bit since my last comment, although I'm still a bit stuck on a few points. My first mistake was that by adding the attached property 'ms:DiagramNodeElement.RaisesBoundsChangeRequested' the control would be handling the resize. Now that I know that is not the case, and that I have to do it, it became a little more clear. Because obviously when I was initially creating the node I provided a hard-coded initial size, which was never changed (unless I manually resized the node), regardless of the actual contents on the node. It still doesn't explain everything that I was seeing, but we can ignore that because those issues have because largely irrelevant. So now I have the following Nod Style, which for the most part works.
And then in the code behind I have this callback:
Pretty simple. However there are still some very weird things happening. When the layout is applied, the callback is triggered with the requested size, the requested Bounds Height is MUCH larger than the controls actually need. The height should be driven by the grid, for which the height is driven by the contents of the property grid, but for some reason the node bounds are about 75% larger than they should be. Selecting the node we can see the node bounds as they are set in the callback. You can also see that the connector lines are positioned based on this very larger size. I am also a bit at a loss at when this callback is triggered. For instance it is called when the mouse passes over the node. That seems weird. But that is not a big deal. What is worse, is that it is triggered again when I select another node - in some cases. If I resize the node to make it shorter than the 'suggested' height, and then select another node, then callback will be triggered to resize the node back to its 'suggested' height. I do not get a callback if I make the node larger. I have tried moving the attached property around to see what would happen, but the results are even stranger. If I put it on the property grid, the node is not even drawn. If I put attached properties on both the parent grid, and the TextBlock, I still have the original problem, but the size of the node is only about 25% bigger than it should be. And I still have the resizing problem when I select another node. Regarding the other issue I had when adding nodes, I guess that answers my question. Ultimately I don't know what I am going to do about that, but that is the least of my problems :) Thanks for your help. |
|
|
Hello Eliz A Grid control actually sizes itself to its parent. The results may be improved if you use a StackPanel as the root of the node template, and put the attached property on that. In the code you posted, you would simply wrap the Grid in a StackPanel. StackPanel definitely sizes itself based on the content. Regarding when the event is raised: At the core style, nodes are split into a low-detail template and a high-detail template. The high-detail template displays all the heavy user controls such as resize thumbs, connection thumbs and rotate thumb. The low-detail template simply displays the node. This greatly improves the performance of editing the DiagramSurface, as the high-detail templates are only used if a node is selected, or if the mouse is over the node. Switching between the templates however causes the whole template to be loaded which in the end results in the size of each element changing and the event being raised. The RaiseBoundsChangeRequested feature and manually resizing nodes don't behave nicely together. What you may need to do is add a custom property on your nodes that know whether they should use auto sizing or manual sizing. You could listen to the BoundsChanged event on each node, and if this was not triggered due to setting the bounds in your event handler, then you could switch it to using manual sizing. Where possible, you may want to disable resizing on some nodes altogether. I hope this gets you further along. -Jason Fauchelle |
|
|
Well, Yes and no :) So, based on your suggestion I changed the template to this:
I still want the border to provide the nice frame, but the StackPanel controls the size. I presume that was approximately what you meant. What happens now, is that the node is still the larger size that it was with my original template, however, it is now drawing the contents to the size that it thinks it should be. See below. That is an improvement at least. I still don't know why it is trying to be that big, but this is a much easier problem to live with. Strange side note though. In my first test of this new template, I had an attached property on the TextBlock as well as the StackPanel. If you remember in my original template this attached property on the TextBlock would make the ultimate size of the node a bit smaller than without it. Now with the stack panel it causes an even more intriguing problem. The initial size of the node is still the TALL size. However, when I mouse over the node - BAM the node resizes smaller. I have removed that attached property on the TextBlock for now to avoid this problem, but I still would like to know why the node thinks it has to be SOOO tall. So, better at least. |
|
|
Hello Eliz Try this: Take the original style that you posted, and put the StackPanel around the Grid tags. So that the StackPanel is the immediate root of the DataTemplate tag, and it only contains a single child - the Grid which contains the rest of the node layout. And then of course make this StackPanel use the attached property. I have not tried this, but I'd expect it to work due to stack panels resizing themselves based on their content. Let me know how this turns out. -Jason Fauchelle |
|
|
Ok, I see. Sorry, I misunderstood what you were saying before. Although the plot thickens... Making that change doesn't actually fix anything - same behaviour as before. However.... If I have the attached property on the Grid instead of the StackPanel it works beautifully.
That's very strange. There must be logical explanation for this. Maybe when the bounds change is sent from the StackPanel, the grid hasn't finalized resolving its size yet. Or something like that. I don't know. I am trying to decide how much I care :) That solves my critical problems for now. I am still trying to define all the behaviour I need, so I appreciate all the help. I definitely have a better understanding of how the diagram control works. Thanks a ton for all your help. |
|
|
Ah, excellent, I was not expecting that behavior, but it's great that you have a solution now. -Jason Fauchelle |
|