Looping through controls on GUI form ?

  • Thread starter Thread starter Z.K.
  • Start date Start date
Z

Z.K.

I have on a form 20 pictureboxes. I would like to loop through them to
assign the images rather than doing it one at a time. I am not exactly
sure how to do this and I was wondering if someone here could help me out.

Z.K.
 
I have on a form 20 pictureboxes. I would like to loop through them to
assign the images rather than doing it one at a time. I am not exactly
sure how to do this and I was wondering if someone here could help me
out.

What part specifically is it that you're having trouble with? Looping?
Getting references to the control instances? Assigning the images?
Something else?
 
Z.K. said:
I have on a form 20 pictureboxes. I would like to loop through them to
assign the images rather than doing it one at a time. I am not exactly
sure how to do this and I was wondering if someone here could help me out.

Something like:

foreach(Control c in Controls)
{
if(c is PictureBox)
{
if(c.Name.StartsWith("prefix"))
{
PictureBox pb = (PictureBox)c;
// do something with pb
}
}
}

Arne
 
C# foreach has a non-feature where it will do a runtime type check and
silently exclude items that don't match.

So you can just do:

foreach (PictureBox pb in Controls) { ... }

which is identical to the more verbose code below
 
Hi Z.K,

Rather than dragging each PictureBox item to your form, I prefer to use
an array and set it manually using code. For example,

Declare your PictureBox array on your main form,

private readonly PictureBox[] pictures = new PictureBox[20];

Then, on your form constructor, initialize each PictureBox;

for (int i = 0; i < 20; i++)
{
pictures = new PictureBox();
pictures.Size = ... // set your size
pictures.Location = ... // set the location
pictures.Image = ... // set your image
}

Controls.AddRange(pictures);

If at later time you would like to re-assign your image, just loop
through the array and set the Image property.

Regards,
 
C# foreach has a non-feature where it will do a runtime type check and
silently exclude items that don't match.

So you can just do:

foreach (PictureBox pb in Controls) { ... }

which is identical to the more verbose code below

Actually, while it's probably more useful to the OP, it's not literally
identical to the code Arne posted. His code filters on the name of the
control, which can be anything. A particularly ornery programmer could
call his form's textbox "pictureBox1" (or "prefixBox1", depending on how
literally one wants to take Arne's code :) ), and then the code would
crash trying to cast the TextBox instance to a PictureBox.

Your example is much safer, though of course it does assume that the OP
wants every PictureBox instance in the form, and has a straight-forward
way of mapping that instance to whatever initialization is appropriate
(something the OP has left out of his question so far).

Pete
 
Peter Duniho said:
Actually, while it's probably more useful to the OP, it's not literally
identical to the code Arne posted. His code filters on the name of the
control, which can be anything. A particularly ornery programmer could
call his form's textbox "pictureBox1" (or "prefixBox1", depending on how
literally one wants to take Arne's code :) ), and then the code would
crash trying to cast the TextBox instance to a PictureBox.

No, Arne did an "is" test, which my loop incorporates. You're right that
the Name.StartsWith check would probably be wanted in addition.

Of course, one can always do:

PictureBox pics = { pictureBox1, pictureBox2, pictureBox3 };
foreach (pb in pics) { ... }
 
Ben said:
C# foreach has a non-feature where it will do a runtime type check and
silently exclude items that don't match.

So you can just do:

foreach (PictureBox pb in Controls) { ... }

What version of C#/.NET does that?

3.0/3.5 gives InvalidCastException.

Arne
 
No, Arne did an "is" test, which my loop incorporates.

Ah, oops. Missed that part somehow.
You're right that the Name.StartsWith check would probably be wanted in
addition.

Of course, one can always do:

PictureBox pics = { pictureBox1, pictureBox2, pictureBox3 };
foreach (pb in pics) { ... }

There's lots of stuff someone _could_ do. With such a vague question,
it's impossible to know what the OP really _does_ want to do. :)

Pete
 
What version of C#/.NET does that?

3.0/3.5 gives InvalidCastException.

I don't remember the specific behavior off the top of my head; but if
you're seeing it throw an exception, I'd bet it always did.

Maybe Ben is thinking of Enumerable.OfType() method?

Pete
 
if I try

string temp = string.Empty;

foreach (PictureBox pb in Controls)
{


// do something with pb
temp += pb.Name;

}

I get this error.

{"Unable to cast object of type 'System.Windows.Forms.Button' to type
'System.Windows.Forms.PictureBox'."}


Z.K.
 
Thanks, but if I try the below code I get an empty string instead of a
string with the names of the pictureboxes.

Z.K.

string temp = string.Empty;

foreach(Control c in Controls)
{
if(c is PictureBox)
{
if(c.Name.StartsWith("pic"))
{
PictureBox pb = (PictureBox)c;
// do something with pb
temp += pb.Name;
}
}
}


------------------
 
Thanks, I will keep this handy for next time. Unfortunately I already
have the pictureboxes on my form so I don't want to redo everything.
Oh, one thing, if it is done dynamically like this, how would I add the
necessary functions. Would not the compiler complain if I added the
methods and the controls were not there until run time?

Z.K.

Hi Z.K,

Rather than dragging each PictureBox item to your form, I prefer to use
an array and set it manually using code. For example,

Declare your PictureBox array on your main form,

private readonly PictureBox[] pictures = new PictureBox[20];

Then, on your form constructor, initialize each PictureBox;

for (int i = 0; i < 20; i++)
{
pictures = new PictureBox();
pictures.Size = ... // set your size
pictures.Location = ... // set the location
pictures.Image = ... // set your image
}

Controls.AddRange(pictures);

If at later time you would like to re-assign your image, just loop
through the array and set the Image property.

Regards,

Z.K. said:
I have on a form 20 pictureboxes. I would like to loop through them
to assign the images rather than doing it one at a time. I am not
exactly sure how to do this and I was wondering if someone here could
help me out.

Z.K.
 
Thanks Peter. I tried some of the other ways, but yours is the only one
that actually works though it is a bit cumbersome having to add each
control manually like that. I would have preferred some way to loop
through the controls that are already on the form, but at least this
works. I used to use control arrays in VB 6. Too bad that feature did
not make it in to C#. I wonder if VB.NET still has that feature as I
have not used VB.NET that much.

Thanks again.

Z.K.
 
Thanks Peter. I tried some of the other ways, but yours is the only one
that actually works though it is a bit cumbersome having to add each
control manually like that.

For the record, I haven't posted any suggested solutions. So I can't take
credit for whatever solution you've found to work. :)

I'm not really clear on what method you're using. "...having to add each
control manually" makes it sound like you're using the array-based
approach suggested by the person posting as "kndg". But you specifically
replied to that person saying you're using some other technique.
I would have preferred some way to loop through the controls that are
already on the form, but at least this works.

Again, not sure what "this" is. But Ben's and Arne's suggestions will
both work fine, if used correctly. If not used correctly then of course,
you may have problems. :)
I used to use control arrays in VB 6. Too bad that feature did not make
it in to C#. I wonder if VB.NET still has that feature as I have not
used VB.NET that much.

I don't know what a "control array in VB 6" is, but you can certainly
create an array of controls in C#.

Pete
 
Thanks, but if I try the below code I get an empty string instead of a
string with the names of the pictureboxes. [...]

Then, in the Control or Form where the code you posted exists, there are
no PictureBox controls that have a name starting with "pic". If that's by
design, then you obviously need to word the code differently, to
accommodate whatever you're actually doing. If it's not by design, then
find out why your PictureBox controls aren't there and/or don't have the
name you expect, and fix that. :)

Pete
 
Z.K. said:
[...] Oh,
one thing, if it is done dynamically like this, how would I add the
necessary functions.

What do you mean by the above statement?
What function? If you mean the event handler, then just add the event
handler to them.
Suppose you want to display a message box whenever the user click the
picture,

private void pictureBox_Click(object sender, EventArgs e)
{
MessageBox.Show("Ouch!");
}

On your form constructor,
...
pictures.Click += pictureBox_Click;
...
Would not the compiler complain if I added the
methods and the controls were not there until run time?

Sorry, I do not understand this either...
If you mean the controls that you had placed on your form using the form
designer, then no worries. The compiler does not look the designer to
compile your code. The designer is just a helping tool to create the
code for you. You can check the "[form name].Designer.cs" for the
generated code.

Regards.
 
Thanks, I will keep this handy for next time. Unfortunately I already
have the pictureboxes on my form so I don't want to redo everything. Oh,
one thing, if it is done dynamically like this, how would I add the
necessary functions. Would not the compiler complain if I added the
methods and the controls were not there until run time?

What "necessary functions"? Are you talking about event handlers? If so,
then you would add them to events as necessary, along with the
initialization code.

Note that a hybrid approach would also work: use the Designer to create
the PictureBox controls in the Form, but then initialize an array with the
individual PictureBox field values after the InitializeComponent() method
has been called.

Finally, you have made a number of comments regarding what doesn't or does
work in your case, but still have not posted a concise-but-complete code
example that actually demonstrates what you're trying to do. If after
these replies you still are unsure of what approach would work for you,
you should put together a proper code example and post it so that it's
clear what you're trying, and why it doesn't work in your case.

Pete
 
Ben Voigt [C++ MVP] submitted this idea :
C# foreach has a non-feature where it will do a runtime type check and
silently exclude items that don't match.

So you can just do:

foreach (PictureBox pb in Controls) { ... }

which is identical to the more verbose code below

No, that doesn't work. If there is a control in the Controls collection
that is not a PictureBox (or derived from that), this will fail (as
others already have said)

What the foreach really silently does is cast every Control from the
Controls collection to PictureBox.

Hans Kesting
 
That doesn't work in .net2.0. Maybe you use the class which override
the GetEnumerator function in the past.

Martin
 
Back
Top