I've got some code that will generically get all Controls in a form and put them in a list. Here's some of the code:
private List<Control> GetControlList(Form parentForm)
{
List<Control> controlList = new List<Control>();
AddControlsToList(parentForm.Controls, controlList);
return controlList;
}
private void AddControlsToList(Control.ControlCollection rootControls, List<Control> controlList)
{
foreach (Control c in rootControls)
{
controlList.Add(c);
if (c.HasChildren)
AddControlsToList(c.Controls, controlList);
//
}
}
So I'm only able to use c.HasChildren to check and see if there's any more child controls from this root control.
What about a menuStrip, toolStrip, and statusStrip? How do I get all of the controls that are in these controls generically? Ex: MenuStripItem
I know that I could try testing the c.GetType() == typeof(MenuStrip) but I was hoping to not have to do specific type tests.
If I need to give more info, please ask.
Thanks a bunch
The items such as ToolStripItem etc aren't actually controls, they are simply components that make up a ToolStrip or MenuStrip.
Which means, that if you want to include those components in your flattened list of controls then you will need to do the specific checks.
I believe the VS designer does it by getting an instance of the control's designer (see the
Designer
attribute), and, if the designer is aComponentDesigner
, getting theAssociatedComponents
property.EDIT:
Okay, I guess that's a little vague. A warning, though: what follows is a little complicated, and might not be worth the effort.
A note on nomenclature:
Below, I will be referring to both the designer within Visual Studio—which is the name used to refer to the functionality within Visual Studio by which the layout and content of forms and controls are edited visually—and to designer classes—which will be explained below. To prevent confusion as to which I am referring to at any given time, I will always refer to the designer functionality within Visual Studio as "the designer", and I will always refer to a designer class as an "IDesigner", which is the interface each must implement.
When the Visual Studio designer loads a component (usually a control, but also things like
Timer
and such), it looks for a custom attribute on the class of typeDesignerAttribute
. (Those unfamiliar with attributes might want read up on them before continuing.)This attribute, if present, provides the name of a class—an IDesigner—the designer can use to interface with the component. In effect, this class controls certain aspects of the designer and of the design-time behavior of the component. There's indeed quite a lot you can do with an IDesigner, but right now we're only interested in one thing.
Most controls that use a custom IDesigner use one that derives from
ControlDesigner
, which itself derives fromComponentDesigner
. TheComponentDesigner
class has a public virtual property calledAssociatedComponents
, which is meant to be overridden in derived classes to return a collection of references to all "child" components of this one.To be more specific, the
ToolStrip
control (and by inheritance, theMenuStrip
control) has aDesignerAttribute
that references a class calledToolStripDesigner
. It looks sort of like:The
ToolStripDesigner
class is not public. It's internal to System.Design.dll. But since it's specified here by it's fully qualified name, the VS designer can useActivator.CreateInstance
to create an instance of it anyway.This
ToolStripDesigner
class, because it inherits [indirectly] fromComponentDesigner
has anAssociatedComponents
property. When you call it you get a newArrayList
that contains references to all the items that have been added to theToolStrip
.So what would your code have to look like to do the same thing? Rather convoluted, but I think I have a working example:
ToolStripControlHost might contain a Control:
...that's if you change argument 1 to type
IEnumerable<Control>
and write your own EnumerateTree function (I think it's great to have one good generic EnumerateTree method).