List controls on a form in C#

[list controls]

There are several ways you can list controls on a form. At design time, you can open the form and then use the dropdown at the top of the Properties window. You can also look inside the file Form1.Designer.cs.

At run time it’s harder to list controls on a form than you might think. The Control class has a Controls property that contains references to the controls inside a particular control. For example, a form’s Controls collection lists all of the controls contained directly on the form.

Unfortunately the Controls collection doesn’t include controls contained in other controls. For example, if a form contains a TabControl that contains a PictureBox, then the PictureBox is not listed in the form’s Controls collection. To find the PictureBox you need to recursively descend through the control tree.

That’s the basic approach. Start at the form and recursively descend into the control tree.

Unfortunately it’s not quite that simple. Some controls don’t use their Controls collection to hold references to the items they contain. For example, a MenuStrip control holds its menu items in its Items property.

To make matters even worse, some objects that you might think are controls are actually components so they don’t even have a Controls property. For example, a ToolStripMenuItem is a component but not a control, and it stores its sub-items in its DropDown property’s Items property.

So to list the form’s controls and control-like components, you need to recursively descend into the user interface hierarchy, following the appropriate properties to find sub-items.

This example uses the following code to add items representing user interface components to a ListBox control.

// List the controls in a ListBox.
private void ListControls(ListBox lst, Object parent, int indent)
{
    string spaces = new string(' ', indent);
    if (parent is ToolStrip)
    {
        // Note that a StatusStrip is also a ToolStrip.
        ToolStrip tool_strip = parent as ToolStrip;
        lst.Items.Add(spaces +
            tool_strip.Name + " (" +
            tool_strip.GetType().Name + ")");
        foreach (ToolStripItem item in tool_strip.Items)
        {
            ListControls(lst, item, indent + 4);
        }
    }
    else if (parent is ToolStripDropDownButton)
    {
        // ToolStripDropDownButton inherits from ToolStripItem
        // so it must come first in this if-else-if sequence.
        ToolStripDropDownButton dropdown_button =
            parent as ToolStripDropDownButton;
        lst.Items.Add(spaces +
            dropdown_button.Name + " (" +
            dropdown_button.GetType().Name + ")");
        ListControls(lst, dropdown_button.DropDown, indent + 4);
    }
    else if (parent is ToolStripSplitButton)
    {
        // ToolStripSplitButton inherits from ToolStripItem
        // so it must come first in this if-else-if sequence.
        ToolStripSplitButton split_button =
            parent as ToolStripSplitButton;
        lst.Items.Add(spaces +
            split_button.Name + " (" +
            split_button.GetType().Name + ")");
        ListControls(lst, split_button.DropDown, indent + 4);
    }
    else if (parent is ToolStripMenuItem)
    {
        // ToolStripMenuItem inherits from ToolStripItem
        // so it must come first in this if-else-if sequence.
        ToolStripMenuItem item = parent as ToolStripMenuItem;
        lst.Items.Add(spaces +
            item.Name + " (" +
            item.GetType().Name + ")");
        ListControls(lst, item.DropDown, indent + 4);
    }
    else if (parent is ToolStripItem)
    {
        ToolStripItem item = parent as ToolStripItem;
        lst.Items.Add(spaces +
            item.Name + " (" +
            item.GetType().Name + ")");
    }
    else if (parent is Control)
    {
        Control control = parent as Control;
        lst.Items.Add(spaces +
            control.Name + " (" +
            control.GetType().Name + ")");
        foreach (Control child in control.Controls)
        {
            ListControls(lst, child, indent + 4);
        }
    }
}

The method takes as parameters the ListBox that should hold the components’ names, a component that should be added to the list, and a number of spaces to indent the component’s entry.

The code uses a series of if-else-if statements to see what kind of object the component is. Each if section follows the same pattern. It converts the component into an object of the appropriate type and adds its name to the ListBox. It then loops through the component’s list of items that it contains and recursively calls the ListControls method for those items. The main difference is in the collection that the component uses to hold its items.

Tool strip menu items are a special case. They have a DropDown property that refers to a ToolStripDropDownMenu. That control inherits from ToolStrip so it holds its sub-items in its Items property.

The following table lists the component types and the properties they use to hold their sub-items.

Object Type Sub-items Property
ToolStrip Items
ToolStripDropDownButton DropDown
ToolStripSplitButton DropDown
ToolStripMenuItem DropDown
ToolStripItem ---
Control Controls

The example program also lists the items in a TreeView control. The following overloaded version of the ListControls method works much as the previous version does except it adds items to a TreeNodeCollection to place them in a TreeView.

// List the controls in a TreeView.
private void ListControls(TreeNodeCollection nodes, Object parent)
{
    if (parent is ToolStrip)
    {
        // Note that a StatusStrip is also a ToolStrip.
        ToolStrip tool_strip = parent as ToolStrip;
        TreeNode new_node = nodes.Add(
            tool_strip.Name + " (" +
            tool_strip.GetType().Name + ")");
        foreach (ToolStripItem item in tool_strip.Items)
        {
            ListControls(new_node.Nodes, item);
        }
    }
    else if (parent is ToolStripDropDownButton)
    {
        // ToolStripDropDownButton inherits from ToolStripItem
        // so it must come first in this if-else-if sequence.
        ToolStripDropDownButton dropdown_button =
            parent as ToolStripDropDownButton;
        TreeNode new_node = nodes.Add(
            dropdown_button.Name + " (" +
            dropdown_button.GetType().Name + ")");
        ListControls(new_node.Nodes, dropdown_button.DropDown);
    }
    else if (parent is ToolStripSplitButton)
    {
        // ToolStripSplitButton inherits from ToolStripItem
        // so it must come first in this if-else-if sequence.
        ToolStripSplitButton split_button =
            parent as ToolStripSplitButton;
        TreeNode new_node = nodes.Add(
            split_button.Name + " (" +
            split_button.GetType().Name + ")");
        ListControls(new_node.Nodes, split_button.DropDown);
    }
    else if (parent is ToolStripMenuItem)
    {
        // ToolStripMenuItem inherits from ToolStripItem
        // so it must come first in this if-else-if sequence.
        ToolStripMenuItem item = parent as ToolStripMenuItem;
        TreeNode new_node = nodes.Add(
            item.Name + " (" +
            item.GetType().Name + ")");
        ListControls(new_node.Nodes, item.DropDown);
    }
    else if (parent is ToolStripItem)
    {
        ToolStripItem item = parent as ToolStripItem;
        TreeNode new_node = nodes.Add(
            item.Name + " (" +
            item.GetType().Name + ")");
    }
    else if (parent is Control)
    {
        Control control = parent as Control;
        TreeNode new_node = nodes.Add(
            control.Name + " (" +
            control.GetType().Name + ")");
        foreach (Control child in control.Controls)
        {
            ListControls(new_node.Nodes, child);
        }
    }
}

The following code shows how the main program uses the two versions of ListControls to list the form’s interface elements.

// List all of the controls on the form.
private void Form1_Load(object sender, EventArgs e)
{
    // List the controls in a ListBox.
    ListControls(lstControls, this, 0);

    // List the controls in a TreeView.
    ListControls(trvControls.Nodes, this);
    trvControls.ExpandAll();
}

Note that this code still doesn’t list every component on the form. For example, it won’t list a Timer control. The form’s components.Components property seems to hold timers at least.

If you find other controls that this example doesn’t search properly, for example if a control uses some other property to hold its sub-items, please post a note in the comments below.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.

This entry was posted in controls, forms, system and tagged , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *