Here's a helper method I find useful in this sort of situation:
public static class TreeExtensions
{
public static IEnumerable<T> SelectRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> getChildren)
{
if (source is null) throw new ArgumentNullException(nameof(source));
if (getChildren is null) throw new ArgumentNullException(nameof(getChildren));
return Iterator();
IEnumerable<T> Iterator()
{
var stack = new Stack<IEnumerator<T>>();
try
{
stack.Push(source.GetEnumerator());
while (stack.Count != 0)
{
var iter = stack.Peek();
if (iter.MoveNext())
{
var current = iter.Current;
yield return current;
var children = getChildren(current);
if (children != null) stack.Push(children.GetEnumerator());
}
else
{
iter.Dispose();
stack.Pop();
}
}
}
finally
{
while (stack.Count != 0)
{
stack.Pop().Dispose();
}
}
}
}
}
With that in place, you can now search your entire control tree using LINQ:
IEnumerable<DataGridView> dataGrids = this.Controls.Cast<Control>()
.SelectRecursive(c => c.HasChildren ? c.Controls.Cast<Control>() : null)
.OfType<DataGridView>();