A have several containers on my WinForm like Panel, SpliContainer, StatusStrip... Each of these containers contains basic elements like buttons or textboxs. I need to iterate thru all form controls (even those in Panels, SplitContainers, StatusStrip) to find some control. I try with recursive function
ListAllControls(Control MainControl)
{
foreach (Control control in MainControl.Controls)
{
if (control.HasChildren)
{
ListAllControls(control);
}
else
{
// do something with this control
}
}
}
but I dont get controls that are in containers!?
UPDATE:
I have a Form with SplitContainer, Panel and StatuStrip. In each of these controls I have several child controls like toolStripStatusLabel1 in StatuStrip1. Problem is when I try to find for example control toolStripStatusLabel1 in StatuStrip via function ListAllControls I can't find it!? I don't know any another approach to get all controls from form. Complete code is here:
class Control_Finder
{
private Control founded_control = null;
public Control Founded_Control
{
get { return founded_control; }
}
public void ListAllControls(Control MainControl, string SearchForControl)
{
foreach (Control control in MainControl.Controls)
{
if (control.HasChildren)
{
ListAllControls(control, SearchForControl);
}
else
{
// check if control has searched name
if (control.Name == SearchForControl)
{
founded_control = control;
return;
}
}
}
}
} // class
Sample:
Form Me = this;
Control_Finder Test = new Control_Finder();
Test.ListAllControls(Me, "toolStripStatusLabel1");
if (Test.Founded_Control != null)
{
MessageBox.Show("I found control " + Test.Founded_Control.Name + "!");
}
else
{
MessageBox.Show("Didn't found! :(");
}
For this sample i get Didn't found :( but if I use StatusStrip1 I get "I found control StatusStrip1!" I hope that the question now more clearly than before.
It would have been better for you to have provided a good, minimal, complete code example that clearly shows your specific scenario. However, based on the information you added to your question, I was able to create what I think is a representative code example. This answer is based on that example.
As commenter LarsTech notes, the
ToolStripStatusLabeldoes not inheritControl. The most specific base class shared byControlandToolStripStatusLabelisComponent. So at the very least, you've got a big problem in your attempt to return an object of typeControland yet still find an instance ofToolStripStatusLabel. Even if you did find the object, you wouldn't be able to cast it toControl.Another issue is that while
ToolStripitself does inherit theControlclass, it does not store its children in theControlsproperty (i.e. in aControlCollectionobject). I presume this is because its children aren'tControlobjects and so could not be stored in aControlCollection. In any case, this means that as you recurse through the object graph of your form, you have to handleToolStripdifferently than other instances ofControlin order to find its children.Here is a sample program that demonstrates one approach that would work (see the bottom of this post for the Designer-generated code that goes with this example):
Form1.cs:
Because of the disjoint nature of the object inheritance for the objects you are dealing with, some special handling must be done:
Controlor not. Instances ofControlstore their name in theControl.Nameproperty, but obviously instances that are notControlobjects won't. They need to be handled specifically by identifying the type where their name property is stored (in this case,ToolStripItem.Name, but do note that there are other non-Controltypes that inheritComponentand each would have to be handled separately). I've added aGetNameForComponent(Component)method to encapsulate this.Control, some will store their children in theControlscollection, while others will not, instead using some other property to reference the collection in which the children are stored. Again, a helper method (in this case,GetChildrenForComponent(Component)) is provided to encapsulate this difference.With these two issues addressed, the basic recursive method to search the graph can then be easily written. Please note that I have made some changes to the basic architecture of the method as compared to yours. It is my opinion that implementing this code as a complete class by itself is unnecessary, and in any case having the result stored in a member of that class rather than simply being returned by the method is particularly wrong.
In my example, I have implemented it simply as a single method that returns the object in question if found.
Also please note that your implementation would not find any object that is itself a container of objects. I have corrected this in my examples as well.
One last note: following the above strategy, you would have to add code for each base class of interest. Maybe the above is sufficient for your needs, or maybe you have other container types that hold non-
Controlobjects and which don't inheritToolStrip. If so, you would have to add additional cases in each of the helper methods as appropriate to those types.An alternative to that would be to use reflection to find the class members that contain e.g. the name and children. Assuming the name is always stored in a property called
Name, that part would be relatively simple.But even in this simple example, using reflection to obtain the children is fairly complicated. Rather than the children always being in a collection object obtained from a property named e.g.
Controls, in one case that's the name but in another case the name isItems. One can dig deeper to e.g. determine the type of objects found in the collection, but the code starts to get excessively complicated at that point.Given that it's debatable whether it really even makes sense to treat
ToolStripchildren the same as regularControlchildren in a form anyway, I would not advise investing much effort in a truly generalized solution. Better to handle individual cases as needed, to remind oneself that what you're doing isn't really such a good idea in the first place. :)Form1.Designer.cs: