1

I know that by using a tag or text one could search for a node and find it.

treeview1.Find(string name, bool searchAllChildren)

But in my code I have a for loop over integer number that does some computation and then I would like to copy the i-th node of a treeview to a new node. For example I want to give i = 3 and it should give me node5 with all children.

Lets we have a structure like the following figure in XML. My aim is to generate a treeview in the following way.

First, copy all nodes and children till nodeIV, then copy the nodes node1, .... node7 and save them under a condition, otherwise creat empty node instead.

-root
    -nodeI
    -nodeII
    -nodeIII
    -nodeIV
       -node1
          -children1
          -children2
          -children3
       -node2
       -node3
          -childrenA
          -childrenB
          -childrenC
       -node4
       -node5
       -node6
          -children
       -node7
          -childrenG
          -childrenR1
          -childrenR2
          -childrenR3
          -children

Is there such a way or just only one can get access to a node by doing,

1 Answers1

3

First, instead of reinventing the wheel, I would take the helper function from my answer to How to flatten tree via LINQ? which is very useful for any tree like structures:

public static class TreeUtils
{
    public static IEnumerable<T> Expand<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> elementSelector)
    {
        var stack = new Stack<IEnumerator<T>>();
        var e = source.GetEnumerator();
        try
        {
            while (true)
            {
                while (e.MoveNext())
                {
                    var item = e.Current;
                    yield return item;
                    var elements = elementSelector(item);
                    if (elements == null) continue;
                    stack.Push(e);
                    e = elements.GetEnumerator();
                }
                if (stack.Count == 0) break;
                e.Dispose();
                e = stack.Pop();
            }
        }
        finally
        {
            e.Dispose();
            while (stack.Count != 0) stack.Pop().Dispose();
        }
    }
}

Then I would create a couple TreeView specific helpers:

public static class TreeViewUtils
{
    public static IEnumerable<TreeNode> AsEnumerable(this TreeNodeCollection source)
    {
        return source.Cast<TreeNode>();
    }

    public static IEnumerable<TreeNode> All(this TreeNodeCollection source)
    {
        return source.AsEnumerable().Expand(node => node.Nodes.Count > 0 ? node.Nodes.AsEnumerable() : null);
    }

    public static TreeNode Find(this TreeNodeCollection source, int index)
    {
        return source.All().Skip(index).FirstOrDefault();
    }
}

Now to get the i-th node of the tree view you can simply use

var node = treeview1.Nodes.Find(i);

Additionally you can get the i-th child node of any node like this

var childNode = node.Nodes.Find(i);

To conclude, I've could easily provided a recursive function that just solves the specific question with less code, but this little utility functions give you much more - foreach support, all nodes of a subtree DFT traversal, LINQ queries (like searching by Tag or some other criteria) etc.

UPDATE

Strange requirement nowadays, but here is the "raw" C# function (no LINQ, no extension methods, no iterator methods) doing just what you need

public static class TreeViewUtils
{
    public static TreeNode FindNode(TreeNodeCollection nodes, int index)
    {
        int offset = -1;
        return FindNode(nodes, ref offset, index);
    }
    private static TreeNode FindNode(TreeNodeCollection nodes, ref int offset, int index)
    {
        for (int i = 0; i < nodes.Count; i++)
        {
            var node = nodes[i];
            if (++offset == index || (node = FindNode(node.Nodes, ref offset, index)) != null)
                return node;
        }
        return null;
    }
}

and the respective usage

var node = TreeViewUtils.FindNode(treeview1.Nodes, i);

or

var childNode = TreeViewUtils.FindNode(node.Nodes, i);
Community
  • 1
  • 1
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • Thanks a lot for your great answer. Is there a possibility not to use LINQ, because I am not allowed to do! –  Jan 21 '16 at 11:24
  • You mean the functions from `System.Linq.Enumerable`? Strange. Are you allowed to write and use **extension** methods? **iterator** functions (like my `Expand`)? – Ivan Stoev Jan 21 '16 at 11:28
  • Thanks a lot! This is what I need. –  Jan 21 '16 at 12:37