Get all components, not controls on a form

O

ozbear

How do I access the collection of components, not controls, at
runtime, that have been dropped into the "tray" in the designer?

Create a new form, drop a Backgroundworker on it.
At run time, over what do I iterate in order to locate this component?

I added a button to the form also, and in the button's Click event
handler tried iterating over the form's component collection but it
is null.

Unfortunately Googling for this generates mostly noise about iterating
over the form's Control collection which is of no value for
non-Control elements that have been dropped on the form.

Oz
 
P

Peter Duniho

ozbear said:
How do I access the collection of components, not controls, at
runtime, that have been dropped into the "tray" in the designer?

AFAIK, there's no reliable to do that.
Create a new form, drop a Backgroundworker on it.
At run time, over what do I iterate in order to locate this component?

For future reference, you can see all of the code generated (and for a
Forms application, everything is code, unlike WPF where there's some XML
too) by opening the *.Designer.cs file in the solution for the form.

If you do that with a form that has a BackgroundWorker in it, you'll
find that while a member field is created and a new instance of
BackgroundWorker is assigned to it in the InitializeComponent() method,
it's not tracked in any other way.

For the items in the "Components" group of the Designer's Toolbox
window, some are added to the "components" IContainer in the Form
sub-class generated by the Designer. For example, a Timer component
will be added to that. From within the Form itself, you could access
this IContainer instance and enumerate components found in it. But that
won't be all the components. Just the ones that for whatever reason the
Designer includes (I don't know what is the deciding factor for that; it
seems kind of random to me).
I added a button to the form also, and in the button's Click event
handler tried iterating over the form's component collection but it
is null.

For controls that you've added, the Form's Controls property, which
returns a ControlCollection, is a good way to get all the child controls
immediately within the Form instance. Note that child controls can
themselves have child controls. You can use the
ControlCollection.Find() method to search the entire sub-tree for a
Control instance with a given name, by passing "true" for the
"searchAllChildren" parameter, but there's no built-in way to actually
_enumerate_ the entire sub-tree. Doing so isn't difficult; a simple
recursive method is sufficient. But it's a little extra work.

Pete
 
O

ozbear

AFAIK, there's no reliable to do that.
Bummer.


For future reference, you can see all of the code generated (and for a
Forms application, everything is code, unlike WPF where there's some XML
too) by opening the *.Designer.cs file in the solution for the form.

If you do that with a form that has a BackgroundWorker in it, you'll
find that while a member field is created and a new instance of
BackgroundWorker is assigned to it in the InitializeComponent() method,
it's not tracked in any other way.

I did look at the generated code but thought there might be some
hidden gizmo that could be interrogated.
For the items in the "Components" group of the Designer's Toolbox
window, some are added to the "components" IContainer in the Form
sub-class generated by the Designer. For example, a Timer component
will be added to that. From within the Form itself, you could access
this IContainer instance and enumerate components found in it. But that
won't be all the components. Just the ones that for whatever reason the
Designer includes (I don't know what is the deciding factor for that; it
seems kind of random to me).

Yes it does.
For controls that you've added, the Form's Controls property, which
returns a ControlCollection, is a good way to get all the child controls
immediately within the Form instance. Note that child controls can
themselves have child controls. You can use the
ControlCollection.Find() method to search the entire sub-tree for a
Control instance with a given name, by passing "true" for the
"searchAllChildren" parameter, but there's no built-in way to actually
_enumerate_ the entire sub-tree. Doing so isn't difficult; a simple
recursive method is sufficient. But it's a little extra work.

Pete

I am not interested in iterating over the Controls, as my original
message states. The purpose of the button and its Click event was
solely to ensure that the form was completely loaded/cooked before
trying to interrogate its components (not controls). I was
initially looking in the form's constructor code after the call
to InitializeComponent but there is no difference.

Thanks for your input. At least now I know to stop searching for a
solution.

Oz
 
P

Peter Duniho

ozbear said:
[...]
Thanks for your input. At least now I know to stop searching for a
solution.

Well, to be clear: there is no built-in solution. You can always use
reflection to access the private fields of a class instance, looking for
references to Component instances.

Of course, whenever reflection seems to be the best available solution
for a problem, that's a red flag that the particulars about the problem
being solved are such that one should probably be looking for a
completely different approach.

In this case, that means questioning whether it really makes sense to
enumerate all of the Component instances that have been added to a Form
sub-class in the Designer. And in fact, asking that question makes some
sense to me.

After all, these are (by default) private members of the class, and it
stands to reason that the only code that _should_ have access to them is
code that already should know about each component anyway. Enumeration
should be superfluous.

There are always exceptions to the rule, of course. After all, it's
tempting to think "well, you can enumerate the Control instances
designed into the Form, why not the other Component instances?" But in
contrast to Control instances, designed components should be few enough
and specific enough in use that I think in this case there's a good
chance the rule applies.

Pete
 
O

ozbear

On Thu, 17 Dec 2009 23:08:34 -0800, Peter Duniho
After all, these are (by default) private members of the class, and it
stands to reason that the only code that _should_ have access to them is
code that already should know about each component anyway. Enumeration
should be superfluous.

There are always exceptions to the rule, of course. After all, it's
tempting to think "well, you can enumerate the Control instances
designed into the Form, why not the other Component instances?" But in
contrast to Control instances, designed components should be few enough
and specific enough in use that I think in this case there's a good
chance the rule applies.

Pete
I think you are over analyzing this. I merely had a large number of
components dropped on for a test/throwaway program that I needed to
collect references to in an array for easier manipulations of them.
No long, drawn out analysis of the "best" way to do this was required,
just whether or not it was possible. You say no, for
BackgroundWorkers anyhow, and that's fine, thanks.

The fact that (you say) that other components, such as Timers, do get
placed in the Components collection would seem to belie the notion
desiring to iterate over non-Control components is questionable
practice. For all we know, it is a bug in the framework that other
components types are not present in that collection, or that timers
are. Either way, inconsistency is rarely a good thing.

Oz
 
P

Peter Duniho

ozbear said:
I think you are over analyzing this.

Well, you're certainly welcome to your opinion.
I merely had a large number of
components dropped on for a test/throwaway program that I needed to
collect references to in an array for easier manipulations of them.
No long, drawn out analysis of the "best" way to do this was required,
just whether or not it was possible. You say no, for
BackgroundWorkers anyhow, and that's fine, thanks.

If you don't mention that you're not writing a real program, why should
anyone else make the assumption that you're not? The fact is, under
ordinary circumstances, my points are valid. If you're writing garbage
code, then obviously "anything goes", but you can't expect people to be
mind-readers and know that without you mentioning it.

Of course, for that matter, if this is just "throwaway" code, what's the
big deal? Just put the things in an array. If you've got time to drag
them into the form, you've got time to do that. Or just use reflection;
even if that's almost always the wrong way to do something, it doesn't
seem to matter in this case whether this is implemented in the wrong way
or the right way.
The fact that (you say) that other components, such as Timers, do get
placed in the Components collection would seem to belie the notion
desiring to iterate over non-Control components is questionable
practice.

Actually, having thought about it some more, I realize that probably the
reason Timer instances are tracked and BackgroundWorker instances aren't
is because the former implements IDisposable, and the latter does not.
More generally, the "components" collection is used by the
Designer-generated code to properly dispose components when the form's
Dispose() method is called.

In other words, the "components" member isn't there for your benefit,
it's for the Designer-generated code's benefit. I don't see how its
presence should in any way be construed as an indication that it makes
sense normally to iterate all the component instances you add to a form.

And of course, in abnormal circumstances when it does make sense, you
can just create your own array or other collection and track them that way.
For all we know, it is a bug in the framework that other
components types are not present in that collection, or that timers
are. Either way, inconsistency is rarely a good thing.

See above. On further reflection, I believe that the behavior is
consistent and likely completely intentional.

Pete
 
O

ozbear

Well, you're certainly welcome to your opinion.


If you don't mention that you're not writing a real program, why should
anyone else make the assumption that you're not? The fact is, under
ordinary circumstances, my points are valid. If you're writing garbage
code, then obviously "anything goes", but you can't expect people to be
mind-readers and know that without you mentioning it.

Of course, for that matter, if this is just "throwaway" code, what's the
big deal? Just put the things in an array. If you've got time to drag
them into the form, you've got time to do that. Or just use reflection;
even if that's almost always the wrong way to do something, it doesn't
seem to matter in this case whether this is implemented in the wrong way
or the right way.


Actually, having thought about it some more, I realize that probably the
reason Timer instances are tracked and BackgroundWorker instances aren't
is because the former implements IDisposable, and the latter does not.
More generally, the "components" collection is used by the
Designer-generated code to properly dispose components when the form's
Dispose() method is called.

In other words, the "components" member isn't there for your benefit,
it's for the Designer-generated code's benefit. I don't see how its
presence should in any way be construed as an indication that it makes
sense normally to iterate all the component instances you add to a form.

And of course, in abnormal circumstances when it does make sense, you
can just create your own array or other collection and track them that way.


See above. On further reflection, I believe that the behavior is
consistent and likely completely intentional.

Pete

Pete,
I think your replies in this thread have gone from helpful, to shrill
bordering on abusive. I have noticed this behaviour in your replies
to others in the past, and it diminishes your credibility

Please dial it back.

Oz
 
P

Peter Duniho

ozbear said:
I think your replies in this thread have gone from helpful, to shrill
bordering on abusive.

You should look up words like "shrill" and "abusive" before you use
them. I've written nothing that could, never mind should, be construed
that way.
I have noticed this behaviour in your replies
to others in the past, and it diminishes your credibility

Just because I don't agree with you, that doesn't mean I should not
state that disagreement, nor that I am somehow being abusive in
expressing that disagreement.
Please dial it back.

Please stop being so thin-skinned. If you can't handle someone stating
a disagreement, and especially can't stand them supporting that
disagreement with factual statements, you probably should not be stating
your own opinions in the first place.

Pete
 
O

ozbear

You should look up words like "shrill" and "abusive" before you use
them. I've written nothing that could, never mind should, be construed
that way.

While you have control over what you post in here, you have little
over how it comes across. Recharacterising my term "throwaway"
with yours "garbage" rates on the abuse scale. Many things can
be learned by throwaway code, indeed, where the documentation is
lacking sometimes that is the only way things can be learned.
This does not make it "garbage".

Ranting about some supposed expectation of being a mindreader rates
on the shrill scale, when no such expectation could be construed,
as does going on about iterating over controls when it was
abundantly clear that that was not the question asked. Your straw,
your man.

Just because I don't agree with you, that doesn't mean I should not
state that disagreement, nor that I am somehow being abusive in
expressing that disagreement.

I don't believe I have disagreed with anything you previously posted
in this thread. In fact, I thanked you, twice, for the information
you provided.
Please stop being so thin-skinned. If you can't handle someone stating
a disagreement, and especially can't stand them supporting that
disagreement with factual statements, you probably should not be stating
your own opinions in the first place.

Pete

Oh *I* can handle it, not to worry, and I have an ample amount of skin

thickness. I rather think the reverse is not true. T'was merely a
suggestion to modify a posting style/attitude the sometimes comes
across as being a demeaning, arrogant, bully.

By all means, have the last word, and Happy Holidays.

Oz
 
P

Peter Duniho

ozbear said:
While you have control over what you post in here, you have little
over how it comes across.

It's odd that you would be able to recognize that, and yet you are
willing to take offense where you have no justifiable reason to believe
any was intended.
Recharacterising my term "throwaway"
with yours "garbage" rates on the abuse scale.

Really? Seriously? _That_ is what upset you?

I can't speak for you. Here, I "throw away" the "garbage". Something
intended to be "thrown away" is by definition "garbage". The two
descriptions are synonymous, and yet you somehow have taken offense.

Bizarre.
Many things can
be learned by throwaway code, indeed, where the documentation is
lacking sometimes that is the only way things can be learned.
This does not make it "garbage".

Sure it does. You intend to throw it away. It's garbage.

I write garbage code all the time. I don't get offended when someone
rightfully calls it "garbage". I was going to throw it away anyway.
Why should I care if someone calls it "garbage"?
Ranting about some supposed expectation of being a mindreader rates
on the shrill scale, [...]

Again, I find your reaction bizarre. I did not "rant" about needing to
be a mindreader. I did point out, in a _single_ statement, that if you
don't write something, there's no way for any of us to know it, unless
we are somehow mindreaders. It was not anywhere close to being a rant,
and what I wrote was absolutely factual. For you to take offense is absurd.
when no such expectation could be construed,
as does going on about iterating over controls when it was
abundantly clear that that was not the question asked. Your straw,
your man.

I brought up the control iteration thing for the benefit of making the
discussion complete. I understand you did not need to iterate controls,
but for you to take offense simply because I wanted to address all the
various possibilities is, again, absurd.
I don't believe I have disagreed with anything you previously posted
in this thread. In fact, I thanked you, twice, for the information
you provided. [...]

If you don't disagree with what I wrote, why are you so upset? It's
weird enough that you might get into such a tither over simple
disagreement, but if you agree with everything I wrote, that's even more
bizarre.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top