2009-09-03 49 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); 
     } 
    } 
}