How to get ALL child controls of a Windows Forms form of a specific type (Button/Textbox)?
Here's another option for you. I tested it by creating a sample application, I then put a GroupBox and a GroupBox inside the initial GroupBox. Inside the nested GroupBox I put 3 TextBox controls and a button. This is the code I used (even includes the recursion you were looking for)
public IEnumerable<Control> GetAll(Control control,Type type)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetAll(ctrl,type))
.Concat(controls)
.Where(c => c.GetType() == type);
}
To test it in the form load event I wanted a count of all controls inside the initial GroupBox
private void Form1_Load(object sender, EventArgs e)
{
var c = GetAll(this,typeof(TextBox));
MessageBox.Show("Total Controls: " + c.Count());
}
And it returned the proper count each time, so I think this will work perfectly for what you're looking for :)
In C# (since you tagged it as such) you could use a LINQ expression like this:
List<Control> c = Controls.OfType<TextBox>().Cast<Control>().ToList();
Edit for recursion:
In this example, you first create the list of controls and then call a method to populate it. Since the method is recursive, it doesn't return the list, it just updates it.
List<Control> ControlList = new List<Control>();
private void GetAllControls(Control container)
{
foreach (Control c in container.Controls)
{
GetAllControls(c);
if (c is TextBox) ControlList.Add(c);
}
}
It may be possible to do this in one LINQ statement using the Descendants
function, though I am not as familiar with it. See this page for more information on that.
Edit 2 to return a collection:
As @ProfK suggested, a method that simply returns the desired controls is probably better practice. To illustrate this I have modified the code as follows:
private IEnumerable<Control> GetAllTextBoxControls(Control container)
{
List<Control> controlList = new List<Control>();
foreach (Control c in container.Controls)
{
controlList.AddRange(GetAllTextBoxControls(c));
if (c is TextBox)
controlList.Add(c);
}
return controlList;
}
This is an improved version of the recursive GetAllControls() that actually works on private vars:
private void Test()
{
List<Control> allTextboxes = GetAllControls(this);
}
private List<Control> GetAllControls(Control container, List<Control> list)
{
foreach (Control c in container.Controls)
{
if (c is TextBox) list.Add(c);
if (c.Controls.Count > 0)
list = GetAllControls(c, list);
}
return list;
}
private List<Control> GetAllControls(Control container)
{
return GetAllControls(container, new List<Control>());
}
I combined a bunch of the previous ideas into one extension method. The benefits here are that you get the correctly typed enumerable back, plus inheritance is handled correctly by OfType()
.
public static IEnumerable<T> FindAllChildrenByType<T>(this Control control)
{
IEnumerable<Control> controls = control.Controls.Cast<Control>();
return controls
.OfType<T>()
.Concat<T>(controls.SelectMany<Control, T>(ctrl => FindAllChildrenByType<T>(ctrl)));
}
You can use a LINQ query to do this. This will query everything on the form that is type TextBox
var c = from controls in this.Controls.OfType<TextBox>()
select controls;