How to Get All Child Controls of a Windows Forms Form of a Specific Type (Button/Textbox)

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 :)

C# How to get child control in specific control

Because your controls have equivalent names, you can transform the name of the control you know, to find the control you want:

foreach(var g in this.Controls.OfType<GroupBox>()){  //'this' is the Form. If all your GroupBoxes are in some other panel/container, use that panel's name instead
var cb = g.Controls[g.Name.Replace("gp", "ck")] as CheckBox;
var pb = g.Controls[g.Name.Replace("gpBox", "pb")] as PictureBox;

//PUT MORE CODE HERE e.g. if(cb.Checked) pb.Image.Save(...)
}

If cb/pb are null you'll need to look into the hierarchy to see why; I can't tell from a screenshot what the control nesting looks like. Indexing a ControlCollection by [some name] brings the first control that is a direct child member of the collection, but remember that controls exist in a tree - if you had a panel inside a groupbox then the checkbox is a child of the panel, not the groupbox (the panel is a child of the groupbox).

If things are deeply nested, you can look at ControlCollection.Find instead - there is a bool youcan specify to make it dig through all children. Note that it returns an array of controls

vb.net Find all child controls in a winform

YOu can change the list to list of objects and use the following code:

Public Sub FindChildren(ByVal parentCtrl As Control, ByRef children As List(Of Object))
If parentCtrl.HasChildren Then
For Each ctrl As Control In parentCtrl.Controls
If TypeOf ctrl Is ToolStrip Then
Dim toll As ToolStrip
toll = ctrl
For Each item In toll.Items

children.Add(item)
Next item

End If
children.Add(ctrl)
Call FindChildren(ctrl, children)
Next ctrl
End If

End Sub

Get the list of Child controls inside a groupbox

I don't know that this is any better.. whether it's easier to read is a matter of opinion:

var validData
= grpBxTargetSensitivity.Controls.OfType<FlowLayoutPanel>()
.SelectMany(c => c.Controls.OfType<Panel>())
.SelectMany(c => c.Controls.OfType<TextBox>())
.All(textbox => !string.IsNullOrWhiteSpace(textbox.Text));

This'll grab all TextBoxes inside of all Panels in all FlowLayoutPanels in your GroupBox, and return true if all of those TextBoxes have a value in them.

How can I get all controls from a Form Including controls in any container?

The simplest option may be to cascade:

public static void SetEnabled(Control control, bool enabled) {
control.Enabled = enabled;
foreach(Control child in control.Controls) {
SetEnabled(child, enabled);
}
}

or similar; you could of course pass a delegate to make it fairly generic:

public static void ApplyAll(Control control, Action<Control> action) {
action(control);
foreach(Control child in control.Controls) {
ApplyAll(child, action);
}
}

then things like:

ApplyAll(this, c => c.Validate());

ApplyAll(this, c => {c.Enabled = false; });

Get all controls of a specific type

Using a bit of LINQ:

foreach(var pb in this.Controls.OfType<PictureBox>())
{
//do stuff
}

However, this will only take care of PictureBoxes in the main container.

Is there a way to iterate through all the controls in my project?

I'm going to ignore Namespace for this. You can add it if you like. But this function does what your function purported to do.

Public Function getAllTypesOfControl(assembly As Assembly) As IEnumerable(Of Type)
Return assembly.GetTypes().
Where(Function(t) t.IsSubclassOf(GetType(ContainerControl))).
SelectMany(Function(container) container.GetFields(BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public)).
Where(Function(f) f.FieldType.IsSubclassOf(GetType(Control))).
Select(Function(f) f.FieldType)
End Function

Now, you are left with all the Types of all the Controls which are defined in Controls which are ContainerControls. This should include controls defined inside Forms and UserControls, as you mentioned.

Can you do something with this? I don't think so, since you are hoping to access instances of controls. To do this, you shouldn't be dealing in the regime of Assembly, rather your runtime, which should have your instantiated controls. I think?

You may want to look at Application.OpenForms, and iterate all open forms, and return all controls.

Public Function getAllInstantiatedControls() As IEnumerable(Of Control)
Return Application.OpenForms.Cast(Of Form).
SelectMany(Function(openForm) openForm.Controls.Cast(Of Control)().
Select(Function(c) c.Controls.Cast(Of Control).Append(c))).
SelectMany(Function(c) c)
End Function

You probably want the second one, because you can't just purely act on Types, as I understand you want to store controls properties. So let me break down your problem. You said

...[components in forms] are stored in my project and i can easly see / modify their details...

yes, but do you know how those details are stored? In fact, they are not stored, but set when the form is constructed. Actually, Visual Studio needs to run InitializeComponent in order to show you the designer - every time you make a change to a control. So the details are in fact stored like this (in the designer code, Form1.Designer.vb) with a Button named Button1 on it.

Design

Sample Image

Form1.Designer.vb

Partial Class Form1
Inherits System.Windows.Forms.Form

Public Sub New()
InitializeComponent()
End Sub

Private Sub InitializeComponent()
' ...
Me.Button1 = New System.Windows.Forms.Button()
'
'Button1
'
Me.Button1.Location = New System.Drawing.Point(157, 103)
Me.Button1.Name = "Button1"
Me.Button1.Size = New System.Drawing.Size(75, 23)
Me.Button1.TabIndex = 3
Me.Button1.Text = "Button1"
Me.Button1.UseVisualStyleBackColor = True
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(203, 114)
Me.Controls.Add(Me.Button1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub

Friend WithEvents Button1 As Button
End Class

You can modify or delete that button and watch the code change or disappear from Form1.Designer.vb. So your "details" are stored in code. This is what the "Visual" in Visual Basic means behind the scenes.

So these details are only set when you run InitializeComponent, which means they are set two ways:

  1. In Visual Studio Form1 Design view
  2. When an application is run and a Form1 instance is created

Other than these two ways, the control properties do NOT have your values, and would only have default values (but this is really an impossible situation and of dubious relevance).

Knowing this, you must access the instances of controls, which is achieved with the Application.OpenForms option. I think you can load all controls, and write to some settings file or database, and also read back and find controls and update them based on the settings file or database. I'm not writing that though. I think I answered your question.



Related Topics



Leave a reply



Submit