5

I am selecting all controls I have in a form

if controls are Treeviews, I'll iterate all nodes they have

I need something like: (And it is my code)

foreach (Control c in PanelSM.Controls)
{
    if (c is TreeView) 
    {    
        TreeNodeCollection myNodes = c.Nodes;//<<<<< Here is a mistake
        foreach (TreeNode n in myNodes)
        {
            String text = rm.GetString(n.Name);
            //And more things
            //...
            //...
            //...
       }
    }
    //...
}

Any idea?

Thank You

Tassisto
  • 9,877
  • 28
  • 100
  • 157
Jean
  • 593
  • 2
  • 6
  • 19

6 Answers6

39

You need to use recursion. A method like this should suffice

IEnumerable<TreeNode> Collect(TreeNodeCollection nodes)
{
    foreach(TreeNode node in nodes)
    {
        yield return node;

        foreach (var child in Collect(node.Nodes))
            yield return child;
    }
}

Then in your method you can just do

 foreach (var node in Collect(tree.Nodes))
 {
     // you will see every child node here
 }
Mark Kram
  • 5,672
  • 7
  • 51
  • 70
Darren Kopp
  • 76,581
  • 9
  • 79
  • 93
11

It's pretty easy:

void TraverseTree(TreeNodeCollection nodes)
{
    foreach (var child in nodes)
    {
        DoSomethingWithNode(child);
        TraverseTree(child.Nodes);
    }
}

And call it with:

TraverseTree(MyTreeView.Nodes);
Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
2

Your mistake is that c is actually a variable of type Control, which does not have a Nodes member. You will need it to cast it as a TreeView type.

You can do either of these two approaches:

if (c is TreeView) 
{
    TreeNodeCollection myNodes = ((TreeView) c).Nodes; // <<--- Note the cast
    ...
}

or

TreeView tv = c as TreeView;
if (tv != null)
{
        TreeNodeCollection myNodes = tv.Nodes;
        ...
}
2

I prefer simplicity, and here is my simple solution:

    protected void TraverseNodes(TreeNodeCollection nodes, string action, int maxDepth = 2) 
    {
        foreach (TreeNode node in nodes)
        {
            if (node.ChildNodes.Count > 0 && node.Depth < maxDepth)
                TraverseNodes(node.ChildNodes, action, maxDepth);

            //do something!!!
            var x = node.Text;
            node.Checked = !node.Checked;
        }
    }

I decided to include a "maximum depth" as a bonus, so enjoy.

Call it as follows:

                TraverseNodes(this.Activities.Nodes, "");

Unlike some of the examples posted here, I actually tested this (ouch! I can hear them say).

Bob Oberst
  • 21
  • 1
0

try this

    foreach (TreeNode t in tvMenu.Nodes)
    {
        for (int iParent = 0; iParent < t.ChildNodes.Count; iParent++)
        {
            for (int iChild = 0; iChild < t.ChildNodes[iParent].ChildNodes.Count; iChild++)
            {
                if (t.ChildNodes[iParent].ChildNodes[iChild].Text == "")
                {

                }
            }
        }
    }
0

Building on top of Darren's great answer, you can combine recursion and class extension.

Declare somewhere in your namespace :

public static class MyExtensions
{
    public static IEnumerable<TreeNode> All( this TreeNodeCollection nodes )
    {
        foreach( TreeNode n in nodes )
        {
            yield return n;
            foreach( TreeNode child in n.Nodes.All( ) )
                yield return child;
        }
    }
}

Note the "this" before the first argument of the method.

Then you can use this new method in all treeviews as:

foreach( TreeNode n in myTreeview.Nodes.All() ) ...
Plasmabubble
  • 153
  • 1
  • 3
  • You can make most any method an extension method. It's not really adding anything to the answer to just turn it into an extension method here. On top of that [you didn't choose a particularly good implementation for traversing the tree to begin with](http://stackoverflow.com/a/10253591/1159478). – Servy Jun 10 '14 at 14:57