Personnalized Compared TreeLayout


I’d like the sorting of the nodes will be made on data structure hierarchical index and not depending order in sourcesnode list.

I define my TreeLayout in code :

fLayout.Comparer = new QDComparer();
fLayout.AlternateComparer = new QDComparer();

With QDComparer :

public class QDComparer : IComparer
public int Compare(TreeVertex a, TreeVertex b)
QD_Node aData = a.Node.Data as QD_Node;
QD_Node bData = a.Node.Data as QD_Node;
if (aData == null)
if (bData == null) return 0;
return 1;
if (bData == null) return -1;
if (aData.HasItem && bData.HasItem)
return Functions.HierarchicalCompare(aData.Item.HierarchicalIndex, aData.Item.HierarchicalIndex);

            return -1; //C'est une note ou une restriction


I set a breakpoint in the Compare function, but when diagram.Layout is called I don’t reach the breakpoint …

Where is my error ?


You also need to set the Sorting property (and the AlternateSorting property).

I set them…

case EQDLayout.TREE_H:
case EQDLayout.TREE_V:
QD_TreeLayout fLayout = new QD_TreeLayout();
fLayout.TreeStyle = TreeStyle.RootOnly;

                    if (type == EQDLayout.TREE_H)
                        fLayout.Angle = 90.0;
                        fLayout.NodeIndent = 120;
                        fLayout.AlternateAngle = 90.0;
                        fLayout.AlternateNodeIndent = 0;
                        fLayout.Angle = 0.0;
                        fLayout.NodeIndent = 0;
                        fLayout.AlternateAngle = 0.0;
                        fLayout.AlternateNodeIndent = 120;                        

                    fLayout.Alignment = TreeAlignment.Start;
                    fLayout.NodeIndentPastParent = 0; //fraction 0-1
                    fLayout.NodeSpacing = 20;
                    fLayout.LayerSpacing = 50;
                    fLayout.LayerSpacingParentOverlap = 0; //fraction 0-1
                    fLayout.Compaction = TreeCompaction.None;
                    fLayout.BreadthLimit = 0;
                    fLayout.RowSpacing = 20;
                    fLayout.RowIndent = 10;
                    fLayout.SetsPortSpot = true;
                    fLayout.SetsChildPortSpot = true;
                    fLayout.Sorting = TreeSorting.Forwards;

                    fLayout.Comparer = new QDComparer();
                    fLayout.AlternateComparer = new QDComparer();

                    fLayout.AlternateAlignment = TreeAlignment.Start;
                    fLayout.AlternateNodeIndentPastParent = 0; //fraction 0-1
                    fLayout.AlternateNodeSpacing = 20;
                    fLayout.AlternateLayerSpacing = 50;
                    fLayout.AlternateLayerSpacingParentOverlap = 0; //fraction 0-1
                    fLayout.AlternateCompaction = TreeCompaction.None;
                    fLayout.AlternateBreadthLimit = 0;
                    fLayout.AlternateRowSpacing = 25;
                    fLayout.AlternateRowIndent = 10;
                    fLayout.AlternateSetsPortSpot = true;
                    fLayout.AlternateSetsChildPortSpot = true;
                    fLayout.AlternateSorting = TreeSorting.Forwards;
                    fLayout.Conditions = LayoutChange.NodeAdded | LayoutChange.LinkAdded;


I can’t be sure based on what you showed above, but it appears that you create and initialize a TreeLayout but never set Diagram.Layout, so that the layout knows what graph to work on and to allow the layout to be invalidated so that it is actually performed.

I’m sure it is the right TreeLayout that it is used, because I’ve made an override of your TreeLayout to test.

Then the breakpoint in LayoutNodes show me that the comparer is the one i’ve defined. (and that the Diagram.Layout is called).

I add a breakpoint in “SortTreeVertexChildren”, I stop on it but not in my comparer.

But the breakpoint in IComparer still unreachable.

Ok, i’ll reproduce my problem in your TLayout Sample.
If I set comparer in code and let treelayout definition in xaml, I stop in Compare function.

But if I do the following :

public TLayout() {

      myDiagram.Model = new GraphLinksModel<SimpleData, String, String, LinkData>();
      myDiagram.Model.Modifiable = true;
      TreeLayout oTreeLayout = new TreeLayout();

      Binding binding = new Binding() { Source = AngleTextBox, Path = new PropertyPath("Text") };
      oTreeLayout.SetBinding(TreeLayout.AngleProperty, binding);
      binding = new Binding() { Source = SortingRadioButtonGroup, Path = new PropertyPath("Tag") };
      oTreeLayout.SetBinding(TreeLayout.SortingProperty, binding);
      binding = new Binding() { Source = AlternateSortingRadioButtonGroup, Path = new PropertyPath("Tag") };
      oTreeLayout.SetBinding(TreeLayout.AlternateSortingProperty, binding);

      myDiagram.Layout = oTreeLayout;

      ((TreeLayout)myDiagram.Layout).Comparer = new SimpleComparer();
      ((TreeLayout)myDiagram.Layout).AlternateComparer = new SimpleComparer();

      GenerateTree_Click(null, null);

the diagram is well layouted. but I don’t stop in Compare…


I just copy/pasted your code (and added a “using System.Windows.Data;”), set a breakpoint in SimpleComparer.Compare, ran my modified GoWpfDemo TLayout sample, and immediately hit the breakpoint.

The issue is that in your application you haven’t set TreeLayout.Sorting to TreeSorting.Ascending or TreeSorting.Descending. Setting it to Forwards (or Backwards) explicitly means that it doesn’t have to call Sort – it just accepts the order in which the children are given (or the reverse if Backwards).

Ok, ok

I haven’t well understood the Sorting enumeration.
It was set to Forwards, i change for Ascending and now all is ok.
I stop in my compare.

Just a final question on this subject : Do the compare function compare only brother nodes or compare parent and child node, or different branch child ?

(because if as I suspect it compare only same branch childs, i can simplify my compare).


TreeLayout.SortTreeVertexChildren sorts the TreeVertex.Children array.

Well, because I have not a tree with a single root, i need also to compare roots of my different trees ?

When I load the diagram I have this configuration:
P1 > V1
> V2

P2 > V3
> V4

Can you tell me if there’s a similar function as for Sort the roots.

(P1 and P2 belongs to the same entity, but I want to not display it).

I thing that the order used to display is the order apparition in SourceNodes collection.

Then if I change by program, P2 becomes before P1.
If I ask for new treelayout, P1 still displayed before P2.

Have you a trick to perform my issue ?


I assume there’s no real root Node, right?

If so, you could artificially add a root vertex to the TreeNetwork that the TreeLayout uses.

Override TreeLayout.MakeNetwork to do something like:

public override TreeNetwork MakeNetwork(IEnumerable<Node> nodes, IEnumerable<Link> links) {
  TreeNetwork net = CreateNetwork();
  net.AddNodesAndLinks(nodes.Where(n => n.Category != "Comment"), links);

  TreeVertex root = net.CreateVertex();
  foreach (Node fakeroot in <i>[your diagram's collection of apparent roots]</i>) {
    net.LinkVertexes(root, net.FindVertex(fakeroot), null);

  return net;

Thanks for your quick reply.

Could you precise me where should I call SortTreeVertexChildren ?

With the override you told me, it is no more called.


It ought to be called, since nothing else has changed, has it?

Except that things have changed, since the root of the tree is now different. The former root vertexes are now child vertexes.

Except for the NodeIndent, it seems as if you really aren’t using the TreeStyle.RootOnly. So it might be easiest if you don’t bother using the Alternate… properties at all, by leaving TreeLayout.TreeStyle at its default value of TreeStyle.Layered.

Then override TreeLayout.AssignTreeVertexValues to set the value(s) that you want on each vertex, when you want them to be different from the values that they inherited from their parent vertex. Presumably you’ll only need to change the TreeVertex.NodeIndent property on those vertexes that represent nodes that are the apparent root Nodes.