49

I have multiple pictureboxes and I need to load random images into them during runtime. So I thought it would be nice to have a collection of all pictureboxes and then assign images to them using a simple loop. But how should I do it? Or maybe are there any other better solutions to such problem?

9 Answers 9

93

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.

Sign up to request clarification or add additional context in comments.

3 Comments

This will not consider PictureBoxes that are nested in other containers.
Alternatively... foreach(PictureBox pb in this.Controls.OfType<PictureBox>()) { //do stuff } Not sure it makes a huge difference, but I tend to have a preference for explicit declaration.
What about for something like this: stackoverflow.com/questions/47182809/…
29

You could use this method:

public static IEnumerable<T> GetControlsOfType<T>(Control root) where T : Control { var t = root as T; if (t != null) yield return t; var container = root as ContainerControl; if (container != null) foreach (Control c in container.Controls) foreach (var i in GetControlsOfType<T>(c)) yield return i; } 

Then you could do something like this:

foreach (var pictureBox in GetControlsOfType<PictureBox>(theForm)) { // ... } 

14 Comments

I think that's actually wordier than just root.Controls.OfType<T>, though.
Oh I see, you made it go down to unlimited depth. Gotcha.
I'm doing something similar. I tried this answer's method, but Control became an ambiguous reference between System.Web.UI and System.Windows.Forms. I could find ContainerControl only in the Forms namespace, not under Web. And ContainerControl wouldn't accept a Web.UI Control. Has anybody else ran into this issue? (I'll work around my problem for now, but really really want to use this simple and elegant answer.)
Strangely enough Panel does not inherit from ContainerControl, I had to go one level up in the Winforms class hierarchy and use ScrollableControl in order to include panel. I'm not sure yet what other issues that this may cause. I may update to only support the containers that I'm looking for.
A year later... This did not work for when items were in Group Boxes that were children of the parent container. Apparently they are not a ContainerControl? That's crazy.
|
9

If you're at least on .NET 3.5 then you have LINQ, which means that since ControlCollection implements IEnumerable you can just do:

var pictureBoxes = Controls.OfType<PictureBox>(); 

2 Comments

This will not consider PictureBoxes that are nested in other containers.
Right. In my defense, the OP didn't really specify whether that was a requirement; but still, it would probably make sense to treat it as such.
6

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; } 

Comments

5

A simple function, easy to understand, recursive, and it works calling it inside any form control:

private void findControlsOfType(Type type, Control.ControlCollection formControls, ref List<Control> controls) { foreach (Control control in formControls) { if (control.GetType() == type) controls.Add(control); if (control.Controls.Count > 0) findControlsOfType(type, control.Controls, ref controls); } } 

You can call it on multiple ways. To get the Buttons:

List<Control> buttons = new List<Control>(); findControlsOfType(typeof(Button), this.Controls, ref buttons); 

To get the Panels:

List<Control> panels = new List<Control>(); findControlsOfType(typeof(Panel), this.Controls, ref panels); 

etc.

1 Comment

This worked great for me, I just altered the if statement a little: if (control.GetType() == type || control.GetType().IsSubclassOf(type))
4

Here's another version since the existing provided ones weren't quite what I had in mind. This one works as an extension method, optionally, and it excludes checking the root/parent container's type. This method is basically a "Get all descendent controls of type T" method:

public static System.Collections.Generic.IEnumerable<T> ControlsOfType<T>(this System.Web.UI.Control control) where T: System.Web.UI.Control{ foreach(System.Web.UI.Control childControl in control.Controls){ if(childControl is T) yield return (T)childControl; foreach(var furtherDescendantControl in childControl.ControlsOfType<T>()) yield return furtherDescendantControl; } } 

Comments

1
 public static List<T> FindControlByType<T>(Control mainControl,bool getAllChild = false) where T :Control { List<T> lt = new List<T>(); for (int i = 0; i < mainControl.Controls.Count; i++) { if (mainControl.Controls[i] is T) lt.Add((T)mainControl.Controls[i]); if (getAllChild) lt.AddRange(FindControlByType<T>(mainControl.Controls[i], getAllChild)); } return lt; } 

Comments

1

This to me is by far the easiest. In my application, I was trying to clear all the textboxes in a panel:

 foreach (Control c in panel.Controls) { if (c.GetType().Name == "TextBox") { c.Text = ""; } } 

1 Comment

I just realized after I posted this answer that is is essentially the same as Zelkovar's answer.
0

Takes Control as container into account:

 private static IEnumerable<T> GetControlsOfType<T>(this Control root) where T : Control { if (root is T t) yield return t; if (root is ContainerControl || root is Control) { var container = root as Control; foreach (Control c in container.Controls) foreach (var i in GetControlsOfType<T>(c)) yield return i; } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.