onsdag 18 februari 2009

Generic FindControl extension method

The other day I needed a way to find controls of a certain type in the control hierarchy, preferably in a recursive fashion. The regular Control.FindControl(string controlID) didn't quite cut it. I created two simple extension methods using Jeff Atwood's recursive version as a starting point. Here's an example of why you might need it and how you can use it.

Lets say eg. that you are dynamically adding custom user controls in a repeater and that you want to retrieve all of them without knowing their exact position in the control tree.

   1:  <asp:Repeater runat="server" DataSource="<%# MyDataSource %>" OnLoad="DataBind">
   2:     <ItemTemplate>
   3:        <My:Customer runat="server" Customer="<%# Container.DataItem as My.Customer %>" />
   4:     </ItemTemplate>
   5:  </asp:Repeater>

I came up with a simple extension method that recursively finds controls of a certain type:

   1:  List<CustomerControl> list = myControl.FindControls<CustomerControl>();

By adding an argument (in the form of a predicate) to the extension method you could easily find controls that has a certain feature enabled, eg. where a checkbox is checked.

This could be useful if you are making some kind of web based adminstration tool that dynamically generates edit controls. When the user hits the save button you could easily find all controls that has a certain feature

   1:  List<CustomerControl> list = myControl.FindControl<CustomerControl>(c =>
   2:     c.CustomerIsEnabled);

Finally, here are the extension methods:

   1:          /// <summary>
   2:          /// Recursively finds controls of a certain type anywhere in the 
   3:          /// controls "sub tree".
   4:          /// </summary>
   5:          public static List<T> FindControls<T>(this Control control) where T : class
   6:          {
   7:              return FindControls<T>(control, null);
   8:          }
   9:          /// <summary>
  10:          /// Recursively finds controls of a certain type that matches the specified predicate
  11:          /// anywhere in the controls "sub tree".
  12:          /// </summary>
  13:          public static List<T> FindControls<T>(this Control control, Predicate<T> predicate) where T : class
  14:          {
  15:              List<T> result = new List<T>();
  16:              foreach (Control childControl in control.Controls)
  17:              {
  18:                  if (childControl is T)
  19:                  {
  20:                      T tmp = childControl as T;
  21:                      if(predicate==null || predicate.Invoke(tmp))
  22:                          result.Add(tmp);
  23:                  }
  24:                  result.AddRange(FindControls<T>(childControl, predicate));
  25:              }
  26:              return result;
  27:          }

Hope you find this useful.

Bloggintresserade