Arrange children

Hi, i want to arrange child nodes after adding them.

i have a TreeLayout that i want to add children to some of the nodes.

in the data template i did :



go:Node.Location="{Binding Path=Data.Location,Mode=TwoWay}"



when my window is loaded, i am calling



model.Load(root, “MyInfo”);



it sets the nodes position good, but i have a problem,

all the nodes that were collapsed before the save (never expanded), and now loaded (collapsed) has location (x and y) 0, so when i expand the parent, the children go to position 0,0.

what i did to fix it,is



node.Location = Spot.BottomCenter.PointInRect(n.Bounds); // start underneath,n is the parent



and then



nodeToMove.Move(node.Location, false);



the problem is when i have multiple children nodes(one is over the other),

How can i arrange the children so they will be underneath the parent,ordered nicely.



Thanks Shlomi.

The Node.Location may be (NaN, NaN). We say that such a node doesn’t have a location.

How did the unexpanded nodes get saved with a location of (0, 0)?
Should they not have been saved as (NaN, NaN)?

How is your TreeLayout declared? If you set the Conditions=“Standard VisibleChanged”, then a layout will happen automatically whenever a node becomes visible or invisible.

Furthermore, if a node is loaded with no location, but it’s visible anyway, that will cause a layout to happen, thereby assigning a good position to the node.

Hi, thanks.

i fixed the problem, i removed the initialization of the Location (with 0,0), and now its working (it has a Nan), but i still have a problem when i call



X.Children.Add(newNode);



the newNode has Nan in the location but it creates the new node over the parent node.

my tree layout declared as Conditions=“Standard VisibleChanged”



Thanks,Shlomi.

You should never be calling X.Children.Add(newNode). I’m surprised you’re not getting an error, although maybe that depends on exactly whose Children you are adding to and when.

If you want to add nodes dynamically, add data to the model. Several samples do this kind of thing, such as the IncrementalTree sample.

Ok, i changed it, thanks, but, now the problem has changed.

when i add data to a node, the tree is changing to its default layout, all the nodes get rearranged and not stays as i saved it, or as it was before the add.

Yes, it performs a layout of the whole diagram, to make sure that there aren’t any overlapping nodes or links.

Adding one node to a tree may cause every node to have to move.

what you are saying, that when a node is added, the location of the old nodes is changing to the default layout of the tree?



If i have an xml that has the last location of all the old nodes (model.Save<…), how can i use it that at list the old nodes will stay at there last location and the new added node will get a new location?



Instead of trying to save and restore the locations of all of the old nodes in XML, I think it would be easier to not perform a layout on the diagram when you add a node.

You can do that by setting the layout Conditions="InitialOnly". That way the layout only happens when the diagram is initialized, and never automatically thereafter. So when you dynamically add a node, you can assign its position yourself, because the existing nodes will not be laid out again.

So, this leads me to my first question:



how can i arrange child nodes after adding them.



when i add multiple children nodes(one is over the other),

How can i arrange the children so they will be underneath the parent,ordered nicely.

Are you asking how you could arrange the subtree consisting of the parent node and all of its children, including the new nodes?

You can do that by having a TreeLayout operate on exactly those nodes, and not on other nodes in the diagram, and by specifying a TreeLayout.Arrangement = "FixedRoots". Something like:
... add new nodes to a parent node ...
var layout = new TreeLayout();
layout.Arrangement = TreeArrangement.FixedRoots;
...set other layout properties...
var subtree = parentnode.FindTreeParts(EffectiveCollectionInclusions.SubTree);
var network = new TreeNetwork();
network.AddNodesAndLinks(subtree.OfType(), subtree.OfType());
layout.Network = network;
layout.DoLayout();
I haven't had the chance to test this code, but I hope it gives you a start.

i added that section, with

layout.LayerSpacing = 50;

layout.NodeSpacing = 20;

layout.Conditions = LayoutChange.All;



when i add a new node and when i expand a node for the first time, but it still set the childs location on the parent node.

This worked for me in the way I think you are expecting:

[code] private void Border_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) {
if (DiagramPanel.IsDoubleClick(e)) {
//… add new nodes to a parent node …
var parentnode = Part.FindAncestor(sender as UIElement);
if (parentnode == null) return;
parentnode.Diagram.StartTransaction(“add some children”);
var parentdata = parentnode.Data as MyNodeData;
for (int i = 0; i < 3; i++) {
var n = new MyNodeData() {
Color=“Red”,
Location=parentnode.Location
};
parentnode.Model.AddNode(n); // also sets n.Key to be unique
parentnode.Model.AddLink(parentdata, null, n, null);
}

    var layout = new TreeLayout();
    layout.Arrangement = TreeArrangement.FixedRoots;
    //... set other layout properties ...
    var subtree = parentnode.FindTreeParts(EffectiveCollectionInclusions.SubTree);
    layout.DoLayout(subtree.OfType<Node>(), subtree.OfType<Link>());
    parentnode.Diagram.CommitTransaction("add some children");
  }
}[/code]

I had also declared this event handler on the main element of the node’s DataTemplate, which is a Border: MouseLeftButtonDown=“Border_MouseLeftButtonDown”

did it and it still not working (the children are drawn over the parent),maybe the problem is with my template?



on dbclick:



var parentdata = node.Data as NodeInfo;

for (int i = 0; i < 3; i++)

{

var n = new NodeInfo()

{

Name = “testing”,

Location = node.Location,

Image = “Images/group.png”,

Category = “NodeTemplate”

};

node.Model.AddNode(n); // also sets n.Key to be unique

node.Model.AddLink(parentdata, null, n, null);

}



var layout = new TreeLayout();

layout.Arrangement = TreeArrangement.FixedRoots;

layout.Angle = 90;

layout.TreeStyle = TreeStyle.Layered;

layout.Id = “tree”;

layout.Conditions = LayoutChange.InitialOnly;

layout.LayerSpacing = 50;

layout.NodeSpacing = 20;



var subtree = node.FindTreeParts(EffectiveCollectionInclusions.SubTree);

layout.DoLayout(subtree.OfType(), subtree.OfType());





my node template:







<Border Style="{x:Null}" BorderThickness=“1” BorderBrush=“Transparent”

Padding=“2,0,2,0” CornerRadius=“3”

Background="{Binding Path=Part.IsDropOntoAccepted ,

Converter={StaticResource theBooleanBrushConverter}}"

go:Part.DropOntoBehavior=“AddsLinkFromNode”

go:Node.SelectionAdorned=“True”

go:Node.IsTreeExpanded=“False”

go:Part.LayoutId=“tree”

go:Part.Selectable=“True”

go:Part.Text="{Binding Path=Data.Name}"

go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}"

go:Node.LocationSpot=“Center”

MouseMove=“myDiagram_MouseMove”

DragEnter=“Border_DragEnter”

DragOver=“Border_DragOver”

ContextMenu="{StaticResource NodeMenu}" >





<RichTextBox MinWidth=“50” IsReadOnly=“True” HorizontalContentAlignment=“Center” BorderBrush="{x:Null}" x:Name=“RichTextBoxName”

local:RichTextBoxHelper.DocumentXaml="{Binding Data.Name}"

VerticalScrollBarVisibility=“Auto” HorizontalScrollBarVisibility=“Auto”

AcceptsReturn=“True”>



<Button x:Name=“myCollapseExpandButton” Cursor=“Hand”

Click=“CollapseExpandButton_Click”

Content="{Binding Path=Node.IsExpandedTree, Converter={StaticResource theButtonConverter}}"

Visibility="{Binding Path=Data.HasChildren, Converter={StaticResource booleanToVisibilityConverter}}"

HorizontalAlignment=“Center” VerticalAlignment=“Center” Width=“20” Height=“20” />











can you help? thanks.

Your DataTemplate looks OK to me, although I wouldn’t bother setting go:Part.LayoutId, and there’s no need in code to set layout.Id or layout.Conditions. But I believe that those cleanups wouldn’t change the behavior.

I suppose you could try debugging this by making sure that the collections passed in the call to DoLayout really are the nodes and links that form the expected subtree of the parent node.

i removed the unnecessary fields, as you said, still not working.



about debugging, it shows the correct subtree, with the relevant nodes and links.

the location of the new nodes is the same as the parent (because i set it), and it doesn’t change after the DoLayout.



the go:diagram is:



<go:Diagram Grid.Row=“1” Grid.Column=“0” Grid.ColumnSpan=“2” x:Name=“myDiagram” Padding=“10”

Stretch=“UniformToFill”

HorizontalContentAlignment=“Center”

VerticalContentAlignment=“Center”

NodeTemplateDictionary="{StaticResource NodeTemplateDictionary}"

LinkTemplate="{StaticResource LinkTemplate}"

MouseDoubleClick=“myDiagram_MouseDoubleClick”>

go:Diagram.Layout

<go:TreeLayout Angle=“90”

Arrangement=“Horizontal”

Conditions=“InitialOnly”

Id=“tree”

LayerSpacing=“50”

NodeSpacing=“20”

TreeStyle=“Layered”

/>

</go:Diagram.Layout >

go:Diagram.LayoutManager

<go:LayoutManager Initial=“InvalidateAll” Animated=“True”/>

</go:Diagram.LayoutManage

</go:Diagram>



any idea? thanks.

Error in the last post:

after testing again, i can see that the location of the new nodes is not the same as the parent, but i don’t see the change in the graph (only in debug i can see that the location parameter is changed, after DoLayout).

any idea why i can’t visually see the change?

Actually, I see that I forgot to wrap the model changes inside a transaction.
I wonder if perhaps you forgot that too?

i forgot, but it still the same…

what i don’t understand, is how the locations of the new nodes are different from the parent(after DoLayout), but, visually, i see the new nodes over the parent.

there isn’t any method to refresh the visual part of the tree?

No, there’s no way to refresh part of the visual tree – that’s done automatically in a separate thread by WPF or Silverlight.

I can’t explain the behavior you are seeing.

Your data-binding of go:Node.Location looks good to me.
But maybe you should check the trace listener output for any warnings or errors.

What i can’t understand, is, that when i call my expand function,

until the line



MyNode.IsExpandedTree = !MyNode.IsExpandedTree;



the Location of the children of MyNode is Nan,

and after that line, the children gets MyNode Location,

until



layout.DoLayout(subtree.OfType(), subtree.OfType());



after that they get a new location, but i don’t see it on the screen.