Accessing all the nodes in TreeView Control

前端 未结 7 1563
小蘑菇
小蘑菇 2020-11-27 22:27

I have a TreeView Control with set of nodes and child nodes. For example:

ROOT has A,B,C.

A has a1, a2, a3 and then

相关标签:
7条回答
  • 2020-11-27 22:51

    You can create an Extension Method that returns a List<TreeNode>.

    Descendants Extension Method

    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();
        }
    }
    

    To get all nodes of a TreeView

    var nodes = this.treeView1.Descendants();
    

    To get all child nodes of a Node

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

    You can also use linq to search between nodes.

    Ancestors Extension Method

    To get ancestors of a node, you may also me interested to Ancestors extension methods.

    0 讨论(0)
  • 2020-11-27 22:57

    I know this thread is quite old and my method doesn't exactly reduce the amount of recursion and it may be slightly slower but it makes my code a bit cleaner.

    I use an extension method for IEnumarable<> to flatten any tree (not just TreeView nodes):

    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)));
    }
    

    I then use this method to get all the nodes of the tree:

    IEnumerable<TreeNode> allNodes = treeView1.Nodes.Cast<TreeNode>()
        .Flatten<TreeNode>(n => n.Nodes.Cast<TreeNode>());
    
    0 讨论(0)
  • 2020-11-27 23:00

    You can use Queue like what i had done in my application :

    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);
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-27 23:02

    I am not the biggest fan of recursion but it seems you must use it. I saw a clever example online mixing recursion with an iterator.

        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;
            }
        }
    
    0 讨论(0)
  • 2020-11-27 23:12

    You can use a recursive function to traverse the whole tree:

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

    You can then call this using:

    Traverse(treeView.Nodes);
    

    and it will walk the whole tree depth first (ie. going down as deep as it can before moving to the next sibling). Passing in the Nodes collection means that this code will deal with trees that have multiple root nodes.

    The example code above will print out the name of the node as well as the full path of that node within the tree.

    0 讨论(0)
  • 2020-11-27 23:14

    Don't use nested loops, but go for an recursive solution like:

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

    Call this function for your root node.

    For your additional question: check the FullPath property.

    0 讨论(0)
提交回复
热议问题