Sunday, April 15, 2007

Dinamically acessing controls in C# .NET

Have you ever needed to create / access controls in your C# .NET applications?
something like substituting the following code:


Button1.Text = "click-me;
Button2.Text = "click-me;
Button3.Text = "click-me;


by this:


for (int i=1 ; i <= 3; i++){
String btn = "Button" + i;
btn.Text = "click-me;
}


Well, if you try the code above in C# you will see that it won't work.
It's because 'btn' is still a string and not a Button Control.
Even if you try to make 'btn' a real Button it still won't be pointing to the control you created in the design mode of Visual Studio:


Button btn = new Button;


Will actually give you a new Button, with a different internal ID (clientID), pointing to a Button other than the one in your UI.

How can you solve this? You can place your Controls in a Hash Table with the Control ID as a key and the control as a value when you create them, you can use reflection or you can iterate between the controls in a page until you find the one you are looking for.

The following code snipet shows you how to retrieve a control by iterating in all the controls in a page. It receives the Control ID and the page (which is a control itself) and returns null or a control matching the given ID. The method is recursive, meaning it calls itself everytime if finds a new control.


// The calling code
// The Control has to be cast to a Button.
// 'this' is the current page and 'btn' the button name
for (int i=1 ; i <= 3; i++){
String btn = "Button" + i;
Button b = (Button) retrieveControl(this, btn);
b.Text = "click-me;
}



// retrieve a control from the active page
// the method iterates between the page controls until it finds the correct
// it calls itself everytime if finds a new control that may have inner controls
protected Control retrieveControl(Control c, string controlName)
{
for (int i = 0; i < c.Controls.Count; i++)
{
Control m = c.Controls[i];
if (m.ClientID != null)
{
if (m.ID.Equals(controlName))
{
return m;
}
else
{
Control x = retrieveControl(m, controlName);
if (x != null) { return x; }
}
}
}
return null;
}


Adding the controls to a Hash Table can be a better idea if you are also creating them dinamically.
Reflection is a powerfull tool that allows you to retrieve information from the assembly but for this purpose it may not be as clear as the code above.

No comments: