Here's a generic extension method to iterate all nodes in any hierarchy:
private static IEnumerable<T> SelectRecursiveIterator<T>(IEnumerable<T> source, Func<T, IEnumerable<T>> getChildren)
{
var stack = new Stack<IEnumerator<T>>();
try
{
stack.Push(source.GetEnumerator());
while (stack.Count != 0)
{
IEnumerator<T> iter = stack.Peek();
if (iter.MoveNext())
{
T current = iter.Current;
yield return current;
IEnumerable<T> children = getChildren(current);
if (children != null) stack.Push(children.GetEnumerator());
}
else
{
iter.Dispose();
stack.Pop();
}
}
}
finally
{
while (stack.Count != 0)
{
stack.Pop().Dispose();
}
}
}
public static IEnumerable<T> SelectRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> getChildren)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (getChildren == null) return source;
return SelectRecursiveIterator(source, getChildren);
}
With that in place, you can iterate all the nodes in your tree, and return either all matching nodes:
static IEnumerable<TreeNode> FindAllNodesByHeader(TreeView tree, string header)
{
return tree.Items.Cast<TreeViewItem>().SelectRecursive(node => node.Items.Cast<TreeViewItem>()).Where(node => node.Header == header);
}
or just the first matching node:
static TreeNode FindFirstNodeByHeader(TreeView tree, string header)
{
return tree.Items.Cast<TreeViewItem>().SelectRecursive(node => node.Items.Cast<TreeViewItem>()).FirstOrDefault(node => node.Header == header);
}