9

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 that a1, a2 also contains some nodes like x1, x2, x3 and so on. Like this many subnodes are there. I know it is possible to use loops with a for loop.

I just want to access all the nodes in TreeView control using one or two for loops.

Is there any algorithm for that or is there any other way?

One more question: Is it is possible to have the path of a tree node in an object or in a string using any library functions? For example:

string S = TreeView1.Nodes[i].Nodes[j].Nodes
TigerhawkT3
  • 48,464
  • 6
  • 60
  • 97
user162558
  • 249
  • 3
  • 7
  • 11

7 Answers7

10

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.

tanascius
  • 53,078
  • 22
  • 114
  • 136
8

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.

adrianbanks
  • 81,306
  • 22
  • 176
  • 206
5

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;
        }
    }
noclayto
  • 160
  • 1
  • 6
3

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.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
2

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>());
stritch000
  • 355
  • 4
  • 10
1

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);
            }
        }
    }
}
M_Mogharrabi
  • 1,369
  • 5
  • 29
  • 57
0

The following code is used for traversing a TreeView's nodes and returning only the leaf nodes:

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

I use it for accessing the filenames in an explorer-like 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);
        }
    }
}
Valid
  • 767
  • 7
  • 14