Click here to Skip to main content
Click here to Skip to main content
Go to top

Controls Iteration

, 5 May 2008
Rate this:
Please Sign up or sign in to vote.
This example shows how to perform recursive controls iteration within a form
ControlsBinary

Introduction

In this article, I will show you how to perform a recursive controls iteration to get all the controls inside a form.

Background

Every form has a collection of controls inside it. This collection can be accessed through this.Controls. To retrieve them, first we are going to create a method called GetControls() (that receives a parameter of type Control.ControlCollection, here called a_oControlCollection) and then use a foreach statement to iterate through a_oControlCollection, as shown below:

private void GetControls(Control.ControlCollection a_oControlCollection)
{
    foreach(Control t_oBaseControl in a_oControlCollection)
    {

    }

This code works fine only if we don't have nested controls, which happens when we use containers, menus and toolbars. So, in this case, we have to iterate through each container to retrieve its controls. But, how can we know if the current control is a common control, a container, a menu or a toolbar? The best way I found is to use a switch statement to check the control's type, as shown in the code below:

switch(t_oBaseControl.GetType().Name)
{

}

Now, we have all the control's types and we have to create a case statement for each type that we want. For those controls that aren't a container, menu or toolbar, we can get them directly, as shown below (adding them to a ComboBox):

case "Button":
case "CheckBox":
case "CheckedListBox":
case "ComboBox":
case "DateTimePicker":
case "Label":
case "LinkLabel":
case "ListBox":
case "ListView":
case "MaskedTextBox":
case "MonthCalendar":
case "NumericUpDown":
case "PictureBox":
case "ProgressBar":
case "RadioButton":
case "RichTextBox":
case "TextBox":
case "WebBrowser":
    cbbControls.Items.Add(t_oBaseControl.Name);
    break;

For the FlowLayoutPanel, GroupBox, Panel and TableLayoutPanel, we are going to add them to the ComboBox and then recursively call the GetControls() method using their ControlCollection, like below:

case "FlowLayoutPanel":
case "GroupBox":
case "Panel":
case "TableLayoutPanel":
    cbbControls.Items.Add(t_oBaseControl.Name);
    GetControls(t_oBaseControl.Controls);
    break;

For the SplitContainer, we're going to do the same for each panel.

case "SplitContainer":
    cbbControls.Items.Add(t_oBaseControl.Name);
    GetControls(((SplitContainer)t_oBaseControl).Panel1.Controls);
    GetControls(((SplitContainer)t_oBaseControl).Panel2.Controls);
    break;

And the same for the TabControl, for each TabPage.

case "TabControl":
    cbbControls.Items.Add(t_oBaseControl.Name);
    foreach(TabPage t_oTabPage in ((TabControl)t_oBaseControl).TabPages)
    {
        cbbControls.Items.Add(t_oTabPage.Name);
        GetControls(t_oTabPage.Controls);
    }
    break;

For the *Strip components, things become annoying. For the MenuStrip, we're going to first iterate through all ToolStripItems and, for each ToolStripMenuItem, call another method called GetMenuItems() (that receives a ToolStripItemCollection), and pass as parameter the DropDownItems property. See below:

case "MenuStrip":
    cbbControls.Items.Add(t_oBaseControl.Name);
    foreach(ToolStripMenuItem t_oMenuItem in ((ToolStrip)t_oBaseControl).Items)
    {
        cbbControls.Items.Add(t_oMenuItem.Name);
        GetMenuItems(t_oMenuItem.DropDownItems);
    }
    break;

For the StatusStrip and ToolStrip, we're going to first use a for statement to iterate through all ToolStripItems. After that, we're going to use a switch statement to check its type. For the ToolStripButton, ToolStripComboBox, ToolStripLabel, ToolStripMenuItem, ToolStripProgressBar, ToolStripStatusLabel and ToolStripTextBox, we can cast them all to ToolStripItem. But for ToolStripSplitButton and ToolStripDropDownButton, we need to cast to their exact type and then call GetMenuItem() passing their DropDownItems as parameter to retrieve the controls nested, as shown below:

case "StatusStrip":
case "ToolStrip":
    cbbControls.Items.Add(t_oBaseControl.Name);
    for(int i = 0;i < ((ToolStrip)t_oBaseControl).Items.Count;i++)
    {
        switch(((ToolStrip)t_oBaseControl).Items[i].GetType().Name)
        {
            case "ToolStripButton":
            case "ToolStripComboBox":
            case "ToolStripLabel":
            case "ToolStripMenuItem":
            case "ToolStripProgressBar":
            case "ToolStripStatusLabel":
            case "ToolStripTextBox":
                ToolStripItem t_oToolStripItem =
                    (ToolStripItem)((ToolStrip)t_oBaseControl).Items[i];
                cbbControls.Items.Add(t_oToolStripItem.Name);
                break;
            case "ToolStripSplitButton":
                ToolStripSplitButton t_oToolStripSplitButton =
                    (ToolStripSplitButton)((ToolStrip)t_oBaseControl).Items[i];
                cbbControls.Items.Add(t_oToolStripSplitButton.Name);
                GetMenuItems(t_oToolStripSplitButton.DropDownItems);
                break;
            case "ToolStripDropDownButton":
                ToolStripDropDownButton t_oToolStripDropDownButton =
                    (ToolStripDropDownButton)((ToolStrip)t_oBaseControl).Items[i];
                cbbControls.Items.Add(t_oToolStripDropDownButton.Name);
                GetMenuItems(t_oToolStripDropDownButton.DropDownItems);
                break;
        }
    }
    break;

Just for example, we can also iterate through all nodes inside a TreeView. Inside a foreach statement, we call method GetNodes() passing as parameter the current TreeNode's Nodes property.

case "TreeView":
    cbbControls.Items.Add(t_oBaseControl.Name);
    foreach(TreeNode t_oTreeNode in ((TreeView)t_oBaseControl).Nodes)
    {
        cbbControls.Items.Add(t_oTreeNode.Name);
        GetNodes(t_oTreeNode.Nodes);
    }
    break;

Below are those two necessary methods mentioned earlier:

private void GetMenuItems(ToolStripItemCollection a_oToolStripItemCollection)
{
    foreach(ToolStripItem t_oToolStripItem in a_oToolStripItemCollection)
    {
        cbbControls.Items.Add(t_oToolStripItem.Name);
            switch(t_oToolStripItem.GetType().Name)
            {
                case "ToolStripMenuItem":
                   GetMenuItems(((ToolStripMenuItem)t_oToolStripItem).DropDownItems);
                   break;
            }
    }
}
private void GetNodes(TreeNodeCollection a_oTreeNodeCollection)
{
    foreach(TreeNode t_oTreeNode in a_oTreeNodeCollection)
    {
        cbbControls.Items.Add(t_oTreeNode.Name);
        GetNodes(t_oTreeNode.Nodes);
    }
}

Using the Code

To use this code, simply call GetControls() inside a form passing this.Controls as a parameter. That's all! As simple as that. I made most of the possible case statements, but a few still have to be implemented. I'll leave this as an exercise for you. Any questions? Let me know!

History

  • April 2008 - First published

Copyright © 2007 Sergio A. B. Petrovcic. All rights reserved. Do not publish to other sites without my express permission. Link to this article in accordance with this site's policies and procedures.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

sergioabp
Engineer
Brazil Brazil
Make programs just for fun!

Comments and Discussions

 
GeneralW o r k s g r e a t ! PinmemberPiet Pelle24-Mar-13 4:40 
GeneralSuggestions PinmemberPIEBALDconsult7-May-08 7:18 
switch(t_oBaseControl.GetType().Name)
 
This is inefficient and short-sighted.
It doesn't take future Controls into account.
A Control derived from any of these, but with an unlisted name, would be skipped.
A Control named for a non-container (e.g. TextBox) might contain children, but they would be skipped.
A developer could develop a "SplitContainer" that doesn't contain Panel1 and Panel2.
 

cbbControls.Items.Add(t_oBaseControl.Name);
 
Each of the cases contains this statement, so put it outside the switch.
 


case "SplitContainer":
case "TabControl":

 
These needn't be separate from the other containers because their children are also in the Controls collection. All Controls contain their children in the Controls collection (unless a developer didn't get the memo).
 
So, as I showed in my earlier post, all Controls may be handled in exactly the same manner. It's just a matter of whether or not the Control has any children and a simple check of Controls.Count is enough to determine that; you do not need to check the type of the Control at all.
 


case "MenuStrip":
case "StatusStrip":
case "ToolStrip":
case "TreeView":

 
OK, Menus and TreeViews may need special handling because their children aren't Controls.
But because they're not Controls, they probably shouldn't be iterated as Controls anyway, but that's up to the developer.
 
(The deprecated MainMenu and MenuItem classes also need special handling to be included, but they're another matter.)
 
Such special handling will require checking the type of the Control, but doing a string compare of its type name is not the way to go; use is or as:
 
if ( t_oBaseControl is System.Windows.Forms.TreeView ) ... ;
 
// This covers both MenuStrip and StatusStrip
if ( t_oBaseControl is System.Windows.Forms.ToolStrip ) ... ; 
 
Likewise, in GetMenuItems, use is or as rather than performing a string compare on the type name:
 
if ( t_oToolStripItem is System.Windows.Forms.ToolStripDropDownItem ) ... ;

GeneralI think you went a bit out of your way. PinmemberPIEBALDconsult6-May-08 10:41 
AnswerRe: I think you went a bit out of your way. Pinmembersergioabp7-May-08 2:47 
GeneralRe: I think you went a bit out of your way. PinmemberPIEBALDconsult7-May-08 4:53 
GeneralRe: I think you went a bit out of your way. Pinmembersergioabp7-May-08 7:12 
GeneralRe: I think you went a bit out of your way. PinmemberPIEBALDconsult7-May-08 7:32 
GeneralRe: I think you went a bit out of your way. PinmemberOddball22-May-08 11:24 
GeneralRe: I think you went a bit out of your way. PinmemberPIEBALDconsult22-May-08 13:01 
GeneralRe: I think you went a bit out of your way. Pinmembervsaratkar16-Jul-09 5:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140916.1 | Last Updated 5 May 2008
Article Copyright 2008 by sergioabp
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid