Reputation: 1783
I need to enumerate over a collection of controls - regardless of their nesting level - that match a given predicate.
Originally the problem occurred, when I needed to set all textbox's in a grids row to ReadOnly
, if a column in that row indicated that the record should not be editable.
Later I realized, that I already solved a problem in the past very much like this one, only with a different criteria (find a single control recursively by its ID).
After trying a few alternatives I came up with a general solution that works. But since I will use this method very often, I wanted to gather possible improvements.
This method will return all child controls matching a predicate:
public static IEnumerable<T> FindChildControls<T>(this Control parentControl,
Predicate<Control> predicate) where T : Control
{
foreach (Control item in parentControl.Controls) {
if (predicate(item))
yield return (T)item;
foreach (T child in item.FindChildControls<T>(predicate)) {
yield return child;
}
}
}
Using this method I can do the following:
var allTxt = Page.FindChildControls<TextBox>(c => c is TextBox);
var submit = Page.FindChildControls<Button>(c => c.ID == "btnSubmit").First();
Upvotes: 1
Views: 1361
Reputation: 3718
You can use a queue to get rid of recursion if you want.
public static IEnumerable<T> FindChildControls<T>(Control parentControl,
Predicate<Control> predicate) where T : Control
{
Queue<Control> q = new Queue<Control>();
foreach (Control item in parentControl.Controls)
{
q.Enqueue(item);
}
while (q.Count > 0)
{
Control item = q.Dequeue();
if (predicate(item))
yield return (T)item;
foreach (Control child in item.Controls)
{
q.Enqueue(child);
}
}
}
Upvotes: 5