While working on an ASP.NET Website with a Master Page, I found a need for a function that could return all the dynamically created controls of a specific type. For instance, when you create a page full of textboxes, you’d like to be able to get/set their values. If you have ever worked with MasterPages, you’ll know how annoying it is to modify dynamically generated controls, since each control’s ID is modified to match the ContentPlaceHolder it resides in.
Below is the code for finding a series of controls based on a parent control (like a ContentPlaceHolder, or a Table)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Linq.Expressions;
/// <summary>
/// Extension Methods
/// </summary>
public static class Extensions
{
#region Find Controls
/// <summary>
/// Finds a series of controls recursively
/// </summary>
/// <typeparam name="T">where T is of type System.Web.UI.Control</typeparam>
/// <param name="parent">The parent control to search</param>
/// <returns>A list of filtered controls based on a supplied type and predicate</returns>
public static List<T> FindControls<T>(this System.Web.UI.Control parent) where T : System.Web.UI.Control {
List<T> foundControls = new List<T>();
FindControls<T>(parent, ref foundControls, null);
return foundControls;
}
/// <summary>
/// Finds a series of controls recursively, based on a predicate
/// </summary>
/// <typeparam name="T">where T is of type System.Web.UI.Control</typeparam>
/// <param name="parent">The parent control to search</param>
/// <param name="predicate">Filter returned controls based on a supplied predicate</param>
/// <returns>A list of filtered controls based on a supplied type and predicate</returns>
public static List<T> FindControls<T>(this System.Web.UI.Control parent, Func<T, bool> predicate) where T : System.Web.UI.Control {
List<T> foundControls = new List<T>();
FindControls<T>(parent, ref foundControls, predicate);
return foundControls;
}
/// <summary>
/// Finds a series of controls recursively, based on a predicate
/// </summary>
/// <typeparam name="T">where T is of type System.Web.UI.Control</typeparam>
/// <param name="parent">The parent control to search</param>
/// <param name="foundControls">A list of filtered controls based on a supplied type and predicate</param>
/// <param name="predicate">Filter returned controls based on a supplied predicate</param>
private static void FindControls<T>(System.Web.UI.Control parent, ref List<T> foundControls, Func<T, bool> predicate) where T : System.Web.UI.Control {
if (parent == null) return;
foreach (Control c in parent.Controls) {
// Check this Control
if (c is T && !c.GetType().IsSubclassOf(typeof(T))) { // The Control isn't a Subclass of T (meaning, it's exactly type T)
if (predicate == null ? true : predicate((T)c)) { // If the predicate isn't null, check the predicate's return values as well
foundControls.Add((T)c); // Control must be valid.
}
}
// Check child Controls
if (c.Controls.Count > 0)
FindControls<T>(c, ref foundControls, predicate);
}
}
#endregion Find Controls
}
It’s used like this: assume you have a list of TextBoxes that you’d ID’d as:
ID = “tbDynamic_23153″,
ID = “tbDynamic_23154″,
… etc …
that correspond to records in a database with ID=23153, ID=23154, etc; however, you also have design-time controls like “tbUserName” and “tbPassword”. If you want only the textboxes that start with “tbDynamic_”, then you’d do the following:
// Get the ContentPlaceHolder that the controls reside in...
ContentPlaceHolder cphContent = Master.FindControl("cphContent") as ContentPlaceHolder;
// Get all Textboxes that start with "tbDynamic_"...
List<TextBox> tbs = cphContent.FindControls<TextBox>(x => x.ID.StartsWith("tbDynamic_"));
// Then you can enumerate your database records and populate the textboxes...
for (var r in QueriedDatabaseRecords) {
var tb = tbs.FirstOrDefault(x => x.ID = string.Format("tbDynamic_{0}", r.ID));
if (tb != null)
tb.Text = r.PropertyValue
}
It would be just as simple to get all CheckBoxes or TableRows. And it can be used when there isn’t a MasterPage, as well.
