代码之家  ›  专栏  ›  技术社区  ›  user162558

访问TreeView控件中的所有节点

  •  8
  • user162558  · 技术社区  · 17 年前

    我有一个 TreeView 具有一组节点和子节点的控件。例如:

    根有a,b,c。

    a有a1,a2,a3,然后a1,a2也包含一些节点,比如x1,x2,x3等等。像这样有许多子节点。我知道用for循环是可能的。

    我只想访问 树视图 使用一个或两个for循环的控件。

    有什么算法可以解决这个问题吗?还有其他方法吗?

    还有一个问题:是否可以使用任何库函数在对象或字符串中使用树节点的路径?例如:

    string S = TreeView1.Nodes[i].Nodes[j].Nodes
    
    7 回复  |  直到 7 年前
        1
  •  9
  •   tanascius    17 年前

    不要使用嵌套循环,而是使用递归解决方案,如:

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

    为根节点调用此函数。

    对于您的附加问题:请检查 FullPath 财产。

        2
  •  6
  •   adrianbanks    17 年前

    可以使用递归函数遍历整个树:

    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 集合意味着此代码将处理具有多个根节点的树。

    上面的示例代码将打印出节点的名称以及 全路径 在树中的那个节点。

        3
  •  5
  •   noclayto    13 年前

    我不是递归的最大粉丝,但似乎你必须使用它。我在网上看到一个聪明的例子,把递归和迭代器混合在一起。

        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;
            }
        }
    
        4
  •  3
  •   Reza Aghaei    7 年前

    可以创建返回方法的扩展方法 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();
        }
    }
    

    获取树视图的所有节点

    var nodes = this.treeView1.Descendants();
    

    获取节点的所有子节点

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

    还可以使用LINQ在节点之间搜索。

    祖先扩展方法

    为了得到一个节点的祖先,你也可以让我感兴趣 Ancestors extension methods .

        5
  •  2
  •   stritch000    11 年前

    我知道这个线程已经很老了,而且我的方法并不能完全减少递归的数量。 它可能稍微慢一点,但它使我的代码更干净一些。

    我使用扩展方法 IEnumarable<> 要展平任何树(不仅仅是TreeView节点):

    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>());
    
        6
  •  1
  •   M_Mogharrabi    13 年前

    您可以使用我在应用程序中所做的队列:

    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);
                }
            }
        }
    }
    
        7
  •  0
  •   Valid    10 年前

    以下代码用于遍历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);
            }
        }
    }