Improving ASP.NET: Finding controls

 

This is part of a series of posts offering ideas to improve ASP.NET.

I’m not a big fan of the FindControl() method (found on System.Web.UI.Control) for these reasons:

  • To prepare for the search, it needs to build a sorted collection of all controls found in the NamingContainer for which its invoked. Fortunately, this happens once per NamingContainer. Unfortunately, this work has to occur with each page request.
  • It looks through the list of all available controls in the naming container. Many controls contain their own child controls which are never assigned IDs by the user. So why would you want to search through those child controls? There should be a way to narrow the search.
  • And the usual: it only searches within one NamingContainer (except when you use the $ syntax, but that’s a special case.)

You may not think you are using FindControl, but each web control that has a property taking an ID, like RangeValidator.ControlToValidate, uses it to retrieve the actual control instance. In my opinion, the user is better served by avoiding FindControl and attaching the control instance directly. I do this throughout the controls of Peter’s Data Entry Suite. Let’s look at how my validator gets the ID to your textbox.


public class BaseValidator : WebControl
{
public string ControlIDToEvaluate { get; set; }
public Control ControlToEvaluate { get; set; }
}

This allows two ways to attach the TextBox to the validator. Users would work with the ASP.NET markup must use ControlIDToEvaluate (and FindControl), but those who are willing to write code can avoid FindControl.


<asp:TextBox id="TextBox1" runat="server" />
<des:RangeValidator id="RangeValidator1" runat="server" />

 

RangeValidator1.ControlToEvaluate = TextBox1;

Keep in mind that ASP.NET already has references to controls found on the page (in this case, RangeValidator1 and TextBox1). The difference is significant in terms of how much CPU time is spent. One assignment as opposed to a search that must prepare a sorted collection before it runs.

I would like to see ASP.NET web controls to offer the same capabilities.

1 Comment

  • Peter,

    How much of a Performance increase do you think you can save by following this approach on an average page?

    Cheers,

    Phil.
    [Peter's comments] Hi Phil. If we could avoid using FindControl everywhere, that would be an amazing cost savings, by eliminating the initial building of a sorted collection of controls within the NamingContainer. (That collection's size could be large if you have a lot of controls, including those that have their own child controls.)
    Controls defined on the page or user control layer always have a reference available because ASP.NET declares fields on the Page and UserControl class hosting each control it owns. So this code in Page_Load has minimal impact:
    Validator.ControlToValidateInstance = TextBox1;
    (ControlToValidateInstance is how MS might create an instance property for ControlToValidate. It does not exist today.)

    Unfortunately templated controls like ListView and FormView do not have this advantage. Templates need you to do some kind of lookup. When the container of that template is a NamingContainer, then the time for FindControl depends on all of the controls you add to the Templates. For small lists of controls, FindControl makes sense.
    Yet I would recommend referencing the actual control through the Controls collections available to you. Suppose the TextBox is the 3rd element in the Controls collection of the Template and the Validator is the 4th. The ItemCreated event for the ListView could do something like this:
    validator = e.Items.Controls[3]; // 3 = the 4th control
    textbox = e.Items.Controls[2];
    validator.ControlToValidateInstance = text;


Comments have been disabled for this content.