Search code examples
c#winformscontrolschildcontrol

Return only a specific type of controls in a container


I use a method like this to return all the controls in a container:

public static IEnumerable<Control> NestedControls(this Control container, bool search_all_children = true)
{
    var stack = new Stack<Control>();
    stack.Push(container);
    do
    {
        var control = stack.Pop();

        foreach (Control child in control.Controls)
        {
            yield return child;
            stack.Push(child);
        }
    }
    while (stack.Count > 0 && search_all_children);
}

And this way I can get all the controls:

var textboxes = panel1.NestedControls().OfType<TextBox>().ToList();

However, with an additional code snippet in the method, I can't get only the controls of a certain type in the container. How should I update the method for a code like the one below?

var textboxes = panel1.NestedControls(TextBox);

Solution

  • You can quite easily change this method to a generic one, to return only children of a specific type:

    public static IEnumerable<T> NestedControls<T>(this Control container, bool search_all_children = true) where T : Control
    {
        var stack = new Stack<Control>();
        stack.Push(container);
        do
        {
            var control = stack.Pop();
    
            foreach (Control child in control.Controls)
            {
                // Admittedly, not the best choice of name here...
                if(child is T childToReturn)
                {
                    yield return childToReturn;
                }
                stack.Push(child);
            }
        }
        while (stack.Count > 0 && search_all_children);
    }
    

    Usage:

    var textboxes = panel1.NestedControls<TextBox>();
    var allNestedControls = panel1.NestedControls<Control>();
    

    You can also very easily add a non-generic overload to return all nested controls without having to specify Control:

    public static IEnumerable<Control> NestedControls(this Control container, bool search_all_children = true) 
       => NestedControls<Control>(container, search_all_children);