2009-09-03 64 views
8

我有一個TreeView控制節點和子節點的集合。例如:訪問TreeView控件中的所有節點

ROOT有A,B,C。

A有A1,A2,A3,然後是A1,A2還包含了諸如X1,X2,X3等一些節點。像這樣的許多子節點在那裏。我知道可以使用for循環。

我只想使用一個或兩個for循環訪問TreeView控件中的所有節點。

是否有任何算法或有任何其他方式?

還有一個問題:是否可以在對象或字符串中使用任何庫函數獲得樹節點的路徑?例如:

string S = TreeView1.Nodes[i].Nodes[j].Nodes 

回答

9

不要使用嵌套的循環,但去像一個遞歸解決方案:

void ListNodes(TreeNode node) 
{ 
    foreach(var subnode in node.Nodes) 
    { 
    ListNodes(subnode); 
    } 
    // Print out node 
} 

調用此函數爲您的根節點。

對於您的其他問題:請檢查FullPath屬性。

5

可以使用遞歸函數來遍歷整個樹:

private void Traverse(TreeNodeCollection nodes) 
{ 
    foreach (TreeNode node in nodes) 
    { 
     Console.WriteLine("{0} -> {1}", node.Name, node.FullPath); 
     Traverse(node.Nodes); 
    } 
} 

然後,您可以調用這個使用:

Traverse(treeView.Nodes); 

,它會先走了整個樹深度(即去。在移動到下一個兄弟姐妹之前儘可能地深入)。傳入Nodes集合意味着此代碼將處理具有多個根節點的樹。

上面的示例代碼將打印出該節點的名稱以及樹中該節點的完整路徑

5

我不是遞歸的最大粉絲,但它似乎你必須使用它。我看到一個巧妙的例子,在線混合遞歸迭代器。

private int GetLevels(TreeNodeCollection treeNodes) 
    { 
     int level = 0; 
     foreach (TreeNode node in TreeTopDown(treeNodes)) 
     { 
      int i = node.Level; 
      if (i > level) level = i; 
     } 
     return level; 
    } 

    //TopDown Iterator 
    private IEnumerable<TreeNode> TreeTopDown(TreeNodeCollection treeNodes) 
    { 
     foreach (TreeNode node in treeNodes) 
     { 
      yield return node; 
      foreach (TreeNode subNode in TreeTopDown(node.Nodes)) yield return subNode;    
     } 
    } 

    //BottomUp Iterator 
    private IEnumerable<TreeNode> TreeBottomUp(TreeNodeCollection treeNodes) 
    { 
     foreach (TreeNode node in treeNodes) 
     { 
      foreach (TreeNode subNode in TreeBottomUp(node.Nodes)) yield return subNode; 
      yield return node; 
     } 
    } 
1

您可以使用隊列就像我在我的應用程序做了:

List<TreeNode> nodes = new List<TreeNode>(); 
Queue<TreeNode> queue = new Queue<TreeNode>(); 

// 
// first insert all the root nodes into the queue. 
// 
foreach(TreeNode root in tree.Nodes) { 
    queue.Enqueue(root); 
} 

while(queue.Count > 0) { 
    TreeNode node = queue.Dequeue(); 
    if(node != null) { 
     // 
     // Add the node to the list of nodes. 
     // 
     nodes.Add(node); 

     if(node.Nodes != null && node.Nodes.Count > 0) { 
      // 
      // Enqueue the child nodes. 
      // 
      foreach(TreeNode child in node.Nodes) { 
       queue.Enqueue(child); 
      } 
     } 
    } 
} 
2

我知道這個線程是很老,我的方法不完全相同減少遞歸它的量可能會稍微慢一點,但它使我的代碼更清潔一些。

我使用的擴展方法爲IEnumarable<>拉平任何樹(不只是樹視圖節點):

public static IEnumerable<T> Flatten<T>(
    this IEnumerable<T> rootNodes, 
    Func<T, IEnumerable<T>> childrenFunction) 
{ 
    return rootNodes.SelectMany(
     child => new[] { child } 
      .Concat((childrenFunction(child) ?? Enumerable.Empty<T>()) 
      .Flatten(childrenFunction))); 
} 

然後我用這種方法來獲得樹的所有節點:

IEnumerable<TreeNode> allNodes = treeView1.Nodes.Cast<TreeNode>() 
    .Flatten<TreeNode>(n => n.Nodes.Cast<TreeNode>()); 
+0

這看起來非常整潔...它可以轉換爲VB.NET嗎? VB可以使用=>運算符嗎? – Grantly 2015-01-26 05:36:42

3

您可以創建一個返回List<TreeNode>的擴展方法。

後裔擴展方法

using System.Linq; 
using System.Windows.Forms; 
using System.Collections.Generic; 

public static class Extensions 
{ 
    public static List<TreeNode> Descendants(this TreeView tree) 
    { 
     var nodes = tree.Nodes.Cast<TreeNode>(); 
     return nodes.SelectMany(x => x.Descendants()).Concat(nodes).ToList(); 
    } 

    public static List<TreeNode> Descendants(this TreeNode node) 
    { 
     var nodes = node.Nodes.Cast<TreeNode>().ToList(); 
     return nodes.SelectMany(x => Descendants(x)).Concat(nodes).ToList(); 
    } 
} 

爲了得到一個TreeView的所有節點

var nodes = this.treeView1.Descendants(); 

獲取一個節點

var nodes = this.treeView1.Nodes[0].Descendants(); 

你也可以使用LINQ的所有子節點在節點之間搜索。

0

下面的代碼用於遍歷一個TreeView的節點,僅返回葉節點:

private IEnumerable<TreeNode> LeafNodes(TreeNode root) 
{ 
    Stack<TreeNode> stack = new Stack<TreeNode>(); 
    stack.Push(root); 
    while (stack.Count > 0) 
    { 
     TreeNode current = stack.Pop(); 
     if (current.Nodes.Count == 0) 
     { 
      yield return current; 
     } 
     else 
     { 
      foreach (TreeNode child in current.Nodes) 
      { 
       stack.Push(child); 
      } 
     } 
    } 
} 

我用它在一個類似瀏覽器的TreeView訪問文件名:

private void LogFileNames() 
{ 
    //There may be more than one node at root level 
    foreach (TreeNode rootNode in FileTreeView.Nodes) 
    { 
     //Print only filenames, not directories 
     foreach (TreeNode leafNode in LeafNodes(rootNode)) 
     { 
      Logger.Info(leafNode.Text); 
     } 
    } 
} 
相關問題