15

I have a treeview control on a windows form UI and it has a few nodes (with multiple child nodes). I want to query the nodes collection so as to, say, 1. select those whose name start with 'x'
2. select those which do not have any data in Node.Tag field.

Can someone please suggest me a way to do this. Linq would make it easy and neat, but I found nothing much on Linq to query TreeNodeCollection.

Thanks,

Dumbo
  • 13,555
  • 54
  • 184
  • 288
ViV
  • 1,998
  • 8
  • 27
  • 54
  • 1
    What is depth of your treeview nodes? if the child nodes have nodes themselves you need a reccursive query. – Dumbo Apr 13 '12 at 11:46
  • For now, I can say depth is just 1. – ViV Apr 13 '12 at 11:48
  • 1
    This Link might help.... [1]: http://stackoverflow.com/questions/1815497/enumerating-collections-that-are-not-inherently-ienumerable/1815600#1815600 – Arif Eqbal Apr 13 '12 at 11:49

3 Answers3

45

Because TreeNodeCollection pre-dates .NET 2.0, it isn't a generic collection, so it doesn't implement IEnumerable<T>, which is the 'master' type for LINQ goodness.

However, you can just call .Cast<TreeNode>() on a TreeNodeCollection, and you get an IEnumerable<TreeNode>, which you can then do all the LINQy goodness to.

(this approach works for any such collection that implements IEnumerable but not IEnumerable<T>)

AakashM
  • 62,551
  • 17
  • 151
  • 186
  • Thanks. Seems like will do. But I have another basic problem. I tried the following: `IEnumerable childNodes = treeView2.Nodes.Cast(); var x = childNodes.Where(node => node.Tag == null);` This doesn't really work because childNodes doesn't really contain 'ALL' child nodes. Basically, I am trying to do this: I have a treeview with n nodes and each node having y child nodes. I want to filter out this entire tree on some criteria. How do I go about it. Can you plz suggest.. – ViV Apr 16 '12 at 04:29
  • 2
    If you want to search the entire tree, a recursive method seems the natural choice. This has probably come up on SO before - a quick search found me [this](http://stackoverflow.com/questions/177277/how-to-get-a-list-of-all-child-nodes-in-a-treeview-in-net) which is in VB.NET but should be readily translatable; there will be many more. – AakashM Apr 16 '12 at 08:02
3

You may try something like this with a Fixpoint operator allowing recursive lambdas

// Fix point operator
public static Func<T, T> Fix<T>(Func<Func<T, T>, Func<T, T>> f)
{
    return t => f(Fix<T>(f))(t);
}

then

// your treeView
var tv = new TreeView();

// Your filter Func
Func<TreeNode, bool> filterStartWithXorNoData =
    node => node.Text.StartsWith("x") || string.IsNullOrEmpty(node.Text);

// Your recursive lambda
var filteredNodes = Fix<IEnumerable<TreeNode>>(
    f =>
    nodeList =>
    nodeList.SelectMany(node => f(node.ChildNodes.Cast<TreeNode>()))
      .Union(nodeList.Where(filterStartWithXorNoData)))
      (tv.Nodes.Cast<TreeNode>());
jbl
  • 15,179
  • 3
  • 34
  • 101
2

I've tried something similar recently and struggled with the LINQ approach due to the nested nodes collection under each parent.

I solved my problem with a recursive function that searched all nodes. Reasonably elegant.

VB:

Private Function FindNode(name As String, root As TreeNode) As TreeNode
    For Each n As TreeNode In root.Nodes
        If n.Name = name Then
            'Found, get out
            Return n

        Else
            'Recursively call FindNode to search this node's children
            Dim soughtNode = FindNode(name, n)
            If soughtNode IsNot Nothing Then
                Return soughtNode
            End If
        End If
    Next

    Return Nothing

End Function
David Osborne
  • 6,436
  • 1
  • 21
  • 35