2014-12-16 17 views
5

Ich möchte eine Baumansicht in C# erstellen, die Datei nach Präfix gruppiert (hier ist das Präfix durch das Trennzeichen _ markiert). Die folgenden Dateien sollten diesen Baum geben:Eine Baumansicht rekursiv erstellen

Files Liste:

p_a 
p_a_test 
p_LIG 
p_p 
p_p_c 
p_p_c2 
p_p_ccc 
p_p_test 
p_tres 
TestLineGraph1 
TestLineGrpah 

Entsprechende Baum:

|--p_ 
    |--p_a 
    |--p_a_test 
    |--p_LIG 
    |--p_p 
    |--p_p_ 
     |--p_p_c 
     |--p_p_c2 
     |--p_p_ccc 
     |--p_p_test 
    |--p_tres 
TestLineGraph1 
TestLineGrpah 

Hier ist mein Versuch, Code:

private GraphUINode(List<string> subNodes, GraphUINode parent, string name, int lvl = 0) 
     : base(parent.m_viewDataSubControl) 
{ 
    parent.Nodes.Add(this); 
    this.Name = name; 
    this.Text = name; 

    string currentPrefix = ""; 
    int pertinentSubNodes = 0; 
    while (pertinentSubNodes < subNodes.Count -1 && subNodes[pertinentSubNodes].Split('_').Length < 2+ lvl) 
     pertinentSubNodes++; 

    for (int i = 0; i <= lvl; i++) 
    { 
     currentPrefix += subNodes[pertinentSubNodes].Split('_')[i] + "_"; 
    } 
    List<String> children = new List<string>(); 
    foreach (string child in subNodes) 
    { 
     // The child is in the same group than the previous one 
     if (child.StartsWith(currentPrefix)) 
     { 
      children.Add(child); 
     } 
     else 
     { 
      // Create a node only if needed 
      if (children.Count > 1) 
      { 
       // Create the new node 
       new GraphUINode(children, this, currentPrefix, lvl + 1); 
       children.Clear(); 
       children.Add(child); 
      } 
      else 
      { 
       new GraphTemplateNode(this, m_viewDataSubControl, child); 
      } 
      currentPrefix = ""; 
      for (int i = 0; i <= lvl; i++) 
      { 
       currentPrefix += child.Split('_')[i] + "_"; 
      }      
     } 
    } 
} 

Aber ich vermisse ein paar diejenigen im Endergebnis:

result

Wie kann ich es zurückbekommen? Auch wenn ich Schritt für Schritt debugge, kann ich den logischen Weg nicht finden.

+3

Warum sollte 'p_a_test' nicht unter einem' p_a_' Knoten sein? – juharr

+0

@juharr Hey, das stimmt! Nun, das ist eine weitere Sache zu beheben :( –

+0

Nicht nur fehlt mindestens eine, Ihre 'p_a_test' sollte nie unter dem Knoten 'p_p' sein. Ich denke, ich würde den Code trennen, zuerst eine hierarchische Darstellung mit Klassen und erstellen rendern Sie das dann mit einem rekursiven Aufruf in eine Baumansicht –

Antwort

4

Also das erste, was wir hier machen wollen, ist, unsere Fäden zu nehmen und sie in einen Baum zu verwandeln. Sobald wir einen Baum haben, ist die Zuordnung dieser Knoten zu einem TreeView ziemlich einfach.

Wir werden für den Baum selbst mit der Definition beginnen:

public class Node<T> 
{ 
    public Node(T value, IEnumerable<Node<T>> children) 
    { 
     Value = value; 
     Children = children; 
    } 
    public T Value { get; private set; } 
    public IEnumerable<Node<T>> Children { get; private set; } 
} 

Nizza und einfach jeder Knoten nur ein Wert ist und eine Sammlung von Kindern.

Als nächstes schreiben wir eine Methode, um eine Sequenz von Sequenzen zu nehmen und daraus einen Baum zu erstellen. Die Idee hierbei ist, dass wir alle Elemente basierend auf dem ersten Wert in ihrer Sequenz gruppieren, einen Knoten für jede Gruppe erstellen und dann die Methode für die Gruppe rekursiv aufrufen, um die untergeordneten Elemente für diesen Knoten zu erhalten.

public static IList<Node<T>> GroupToTree<T>(this IEnumerable<IEnumerable<T>> source) 
{ 
    return GroupToTree(source.Select(sequence => sequence.GetEnumerator())); 
} 

private static IList<Node<T>> GroupToTree<T>(IEnumerable<IEnumerator<T>> source) 
{ 
    return source.WhereHasNext() 
     .GroupBy(iterator => iterator.Current) 
     .Select(group => new Node<T>(group.Key, GroupToTree(group))) 
     .ToList(); 
} 

//This ensures that the iterators all get disposed 
private static IEnumerable<IEnumerator<T>> WhereHasNext<T>(
    this IEnumerable<IEnumerator<T>> source) 
{ 
    foreach (var iterator in source) 
    { 
     if (iterator.MoveNext()) 
      yield return iterator; 
     else 
      iterator.Dispose(); 
    } 
} 

Jetzt können wir die Rohdaten nehmen, jede der Saiten in Sequenzen von Strings aufgeteilt, und dann jeder der Knoten zuordnen, die wir hier in UI-basierten Knoten für die Präsentation haben:

List<string> rawData = new List<string>(); 
//TODO populate raw data 
Func<Node<string>, TreeNode> selector = null; 
selector = node => new TreeNode(node.Value, node.Children.Select(selector).ToArray()); 
var nodes = rawData.Select(line => line.Split('_').AsEnumerable()) 
    .GroupToTree() 
    .Select(selector); 
Verwandte Themen