Uniform TreeLayout spacing across descendants?

I’m using a tree layout with vertices of varying sizes and I would like to have all descendants at a given depth from a vertex to be at the same level.

Using the "Class Hierarchy" sample to clarify, I'd like to have the various converters (the children of "Converter") line up with the various models (the children of "DiagramModel"). Similarly, the leaf models under "DiagramModel" should line up vertically as well. As far as I'm concerned, the link lengths can vary. The "Org Chart Static" sample could also have been used.
My back-up plan is to guarantee that my vertices are of a uniform size but I was hoping that I'm missing some obvious property that gives me the behavior I'd like.

That’s on the list of requested features. Let me see what’s been done there, if anything.

OK, the following code only works with horizontally growing trees (i.e. Angle == 0 or Angle == 180):

[code] // This assumes the tree only grows horizontally: Angle == 0 or 180
public class CustomTreeLayout : TreeLayout {
// Assign each TreeVertex.Bounds.Width to be the same for all vertexes in the same layer,
// and just big enough to hold any vertex in that layer.
// This will cause all of the nodes in any layer to be aligned with each other.
protected override void LayoutTree(TreeVertex v) {
// compute maximum tree depth for all trees (not just the one with V at the root)
int maxdepth = 0;
foreach (Node root in this.Roots) {
TreeVertex rootv = this.Network.FindVertex(root);
if (rootv == null) continue;
maxdepth = Math.Max(maxdepth, rootv.MaxGenerationCount + 1);
}

  // this array remembers the needed width for each layer of nodes
  double[] allwidths = new double[maxdepth];

  // find out how wide each layer must be
  foreach (TreeVertex t in this.Network.Vertexes) {
    double d = allwidths[t.Level];
    allwidths[t.Level] = Math.Max(d, t.Bounds.Width);
  }

  // assign all TreeVertex.Bounds.Width values
  foreach (TreeVertex t in this.Network.Vertexes) {
    Rect b = v.Bounds;
    b.Width = allwidths[v.Level];
    v.Bounds = b;
  }

  // now do the normal tree layout
  base.LayoutTree(v);
}

// If links are orthogonal, modify their middle points so that the vertical segments
// in each layer are all co-linear.
protected override void LayoutLinks() {
  foreach (TreeVertex v in this.Network.Vertexes) {
    double x = (v.Angle == 0) ? Double.PositiveInfinity : Double.NegativeInfinity;
    foreach (TreeEdge e in v.DestinationEdges) {
      if (v.Angle == 0) {
        x = Math.Min(x, e.ToVertex.Bounds.Left);
      } else {
        x = Math.Max(x, e.ToVertex.Bounds.Right);
      }
    }
    if (Double.IsInfinity(x)) continue;
    foreach (TreeEdge e in v.DestinationEdges) {
      Link link = e.Link;
      if (link == null) continue;
      Route route = link.Route;
      if (route.Routing == LinkRouting.Normal) continue;
      // require orthogonal links
      Point p2 = route.GetPoint(2);
      Point p3 = route.GetPoint(3);
      if (v.Angle == 0) {
        p2.X = x - 25;
        p3.X = x - 25;
      } else {
        p2.X = x + 25;
        p3.X = x + 25;
      }
      route.SetPoint(2, p2);
      route.SetPoint(3, p3);
    }
  }
  base.LayoutLinks();
}

}[/code]
This works by assigning a TreeVertex.Bounds.Width to each TreeVertex that is wide enough to hold all of the nodes/vertexes that are in that layer. This means you do not have to change the width of each Node.

This also changes the routes of orthogonal links by making sure the vertical middle segments are all co-linear and near the children. This should help reduce unintentional link crossings over nodes when the nodes have dramatically differing sizes.

If you want to handle vertical trees (e.g. Angle == 90), you’ll need to adapt this code.