Find all child controls of specific type using Enumerable.OfType<T>() or LINQ
Asked Answered
C

4

15

Existed MyControl1.Controls.OfType<RadioButton>() searches only thru initial collection and do not enters to children.

Is it possible to find all child controls of specific type using Enumerable.OfType<T>() or LINQ without writing own recursive method? Like this.

Chuckwalla answered 5/2, 2010 at 19:36 Comment(0)
L
43

I use an extension method to flatten control hierarchy and then apply filters, so that's using own recursive method.

The method looks like this

public static IEnumerable<Control> FlattenChildren(this Control control)
{
  var children = control.Controls.Cast<Control>();
  return children.SelectMany(c => FlattenChildren(c)).Concat(children);
}
Letsou answered 5/2, 2010 at 19:42 Comment(1)
Simple, elegant, does the job. +1. You could also specify a desired child type as a generic parameter, and use OfType() instead of Cast, to produce the list in one shot (avoids having to go through all the controls again to filter them).Arondell
B
1

To improve above answer it would make sense to change the return type to

//Returns all controls of a certain type in all levels:
public static IEnumerable<TheControlType> AllControls<TheControlType>( this Control theStartControl ) where TheControlType : Control
{
   var controlsInThisLevel = theStartControl.Controls.Cast<Control>();
   return controlsInThisLevel.SelectMany( AllControls<TheControlType> ).Concat( controlsInThisLevel.OfType<TheControlType>() );
}

//(Another way) Returns all controls of a certain type in all levels, integrity derivation:
public static IEnumerable<TheControlType> AllControlsOfType<TheControlType>( this Control theStartControl ) where TheControlType : Control
{
   return theStartControl.AllControls().OfType<TheControlType>();
}
Brigettebrigg answered 25/7, 2013 at 12:49 Comment(0)
P
1

I use this generic recursive method:

The assumption of this method is that if the control is T than the method does not look in its children. If you need also to look to its children you can easily change it accordingly.

public static IList<T> GetAllControlsRecusrvive<T>(Control control) where T :Control 
{
    var rtn = new List<T>();
    foreach (Control item in control.Controls)
    {
        var ctr = item as T;
        if (ctr!=null)
        {
            rtn.Add(ctr);
        }
        else
        {
            rtn.AddRange(GetAllControlsRecusrvive<T>(item));
        }

    }
    return rtn;
}
Prenatal answered 22/4, 2014 at 8:51 Comment(0)
A
0

I liked this answer (https://mcmap.net/q/758960/-find-all-child-controls-of-specific-type-using-enumerable-oftype-lt-t-gt-or-linq) 12 years later and wanted to do what KeithS suggested and build in the option to pass in a type constraint to return only the type of controls you are after.

Extension Methods

using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace MyApp.Extensions
{
    public static class ControlExtensions
    {
        public static IEnumerable<Control> FlattenChildren<T>(this Control control)
        {
            return control.FlattenChildren().OfType<T>().Cast<Control>();
        }

        public static IEnumerable<Control> FlattenChildren(this Control control)
        {
            var children = control.Controls.Cast<Control>();
            return children.SelectMany(c => FlattenChildren(c)).Concat(children);
        }
    }
}

Example Usage

Added to the form's _Load event...

//Show the name of each ComboBox on a form (even nested controls)
foreach (ComboBox cb in this.FlattenChildren<ComboBox>())
{
    Debug.WriteLine(cb.Name);
}

//Get the number of controls on a form
Debug.WriteLine("Control count on form: " + this.FlattenChildren().Count());
Anson answered 28/10, 2022 at 15:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.