Monday, September 10, 2007

Get a handle on controls

A common inconvenience is that in ASP.NET, controls that are part of templates are not directly accessible from code, frequently resulting in code like this:

TextBox myTextBox = wizardStep.FindControl("MyTextBox") as TextBox;
This has the added problem associated with the late binding of the control to an embedded text string ("MyTextBox"), a misspelling won't be discovered until the run-time hits this code. There's also no real assurance that it'll work as expected, since the the control found may in fact not even be a TextBox. Finally, FindControl() is not recursive, so you have to keep track of the exact correct container. All this is error prone and inconvenient.

It's been source of irritation for some time for me, and I've handled it in various ways in my code. Today I spent an hour doing this in a better way. Enter the ControlReference class, which looks like this:

public class ControlReference<T> where T : Control{ private EventHandler _eventHandler; public ControlReference(EventHandler eventHandler)
{
_eventHandler = eventHandler;
}
public ControlReference() { } private T _control; public T Control
{
get { return _control; } set { _control = value; }
}
public void OnInit(object sender, EventArgs e)
{
Control = (T)sender;
if (_eventHandler != null)
{
_eventHandler(sender, e);
}
}
}

(Formatting somewhat condensed for this format.)
When using this inside the template, you hook the OnInit event in the markup, like this:

<asp:TextBox runat="server" ID="MyTextBox" OnInit="myTextBox.OnInit" />
In the code, all you do is:

protected ControlReference<TextBox> myTextBox = new ControlReference<TextBox>();
...
myTextBox.Control.ForeColor = Color.Red;
This makes it easy, convenient and safe to refer to controls in templates

No comments:

Post a Comment