logo


Walking the Windows Forms Control Hierarchy
By Peter A. Bromberg, Ph.D.

Peter Bromberg

"He polished up the scuppers with a hand so free that now he is the ruler of the Queen's Navy"
       -- H.M.S. Pinafore, Gilbert and Sullivan

In H.M.S. Pinafore, which first premiered at the Opera Comique in London on May 25, 1878, Gilbert and Sullivan satirized the snobbery and hypocrisy of the English social system of their day. The musical was so popular that by the time the official New York premiere took place at the Standard Theatre on January 15, 1879, there had already been numerous pirated versions presented in the city (e.g., the "BETA" was leaked by the Pirates from the Scuppers). The musical has had over 26 runs at various Broadway theaters since then, and too many to count in other cities and countries. (If you would like to hear a short snippet, right - click the icon and choose "play"):



Why do I make reference to H.M.S. Pinafore? It just sounded appropriate. When I was a kid, we had a recording of it and I used to lie on the floor under our big speaker enclosure and listen to it. It was heavenly! I never dreamed that if I polished up my scuppers I"d become a software programmer one day!

The ASP.NET Page class has a neat intrinsic method "FindControl" that enables you to get a runtime reference to any control on the page. It makes dynamic control creation and manipulation much easier. Unfortunately, there is no such animal in Windows Forms. And so, since I needed one, I decided it would be a right good time to polish up those scuppers and make one. There are a lot of ways to "skin a .NET cat", so please just look at this as one approach.

The key thing to understand about the Windows Forms control hierarchy is that it starts with the Form itself, which is a control. So if you have a method that receives the name of a control, if you can gain access to the parent Form, no matter how many levels "up in the hierarchy" it may be, you can begin to figure out what to do. the "FindForm" method of Control is just what we need for this purpose; it puts us right at the top of the hierarchy.

It occured to me that while you can "walk" the Control hierarchy every time you need to find a control, it might be more efficient to do it once, store the Controls and their names, and thereafter we would only need to do a lookup based on the Control's Name property. For this, the Hashtable is ideal. So, we start out with a private - level Hashtable.

Then we need to have a method "FindControlByName" which will accept the name of a control we want to gain access to. As mentioned, first we use the FindForm method on on our class to cast it to a Form we can work with. Then, we check to see if our Hashtable has already been filled by a previous call to the method. If the Count is zero, we call the recursive method "AddControlToHashTable( ControlName, Control).

AddControlToHashtable simply adds the control to our Hashtable, using the Control's Name property as the key. Then, it asks if this control HasChildren. If it does, the method then calls itself on each child control in that collection. In this manner, it doesn't matter how many levels of child controls we may have in our Control Hierarchy, they will all be added to our HashTable. And now that they are all there, any subsequent lookups will be faster.

Finally, the FindControlByName method simply does a HashTable lookup and sends us back the Control we were searching for. In the button2_Click method, you can see that we are simply changing the BackColor property of the found control on the Form as a "proof of Concept"

 System.Collections.Hashtable htFrm=new System.Collections.Hashtable();
private Control FindControlByName(string ctrlName)
{
 Form frm = this.FindForm();
  if(htFrm.Count ==0) 
{   AddControlToHashTable(frm.Name ,frm); } return (Control)htFrm[ctrlName]; } private void AddControlToHashTable(string ctrlName, Control Ctrl) { htFrm[ctrlName]=Ctrl; if(Ctrl.HasChildren) { foreach(Control ctrl2 in Ctrl.Controls ) // recursive call adds all controls and any children AddControlToHashTable(ctrl2.Name,ctrl2); } } private void button2_Click(object sender, System.EventArgs e) { if(txtControlName.Text=="") { MessageBox.Show("Enter a control Name, Captain!"); return; } Control c = FindControlByName(txtControlName.Text); c.BackColor=Color.AntiqueWhite ; }

The Result on the sample downloadable solution would look like this:

As can be seen, our method had no difficulty finding and highlighting "linkLabel1", which is three levels down in the hierarchy.

Download the Solution that accompanies this article

 


Peter Bromberg is a C# MVP, MCP, and .NET consultant who has worked in the banking and financial industry for 20 years. He has architected and developed web - based corporate distributed application solutions since 1995, and focuses exclusively on the .NET Platform. Pete's samples at GotDotNet.com have been downloaded over 41,000 times. You can read Peter's UnBlog Here.  --><--NOTE: Post QUESTIONS on FORUMS!
Article Discussion: