Friday, 1 May 2009

Listing All Controls on a Form and Flattening Hierarchies

For an application I'm developing it is necessary to enumerate my way through all the controls of a form. Using the Controls property only gives the immediate children, so it must be called recursively in order to retrieve all the controls. This started me thinking. Wouldn't it be easier to have a function that could flatten out any hierarchy so it could be easily enumerated?

At first I thought I'd just used IEnumerable.SelectMany, but again I fell foul of the deferred execution. Also some nasty jiggery-pokery would have been necessary to ensure I just didn't end up enumerating only the controls at the bottom of the hierarchy.

My solution is this simple method:
IEnumerable<T> Flatten<T>(T parent, Func<T, IEnumerable<T>> childFunction)
{
yield return parent;
foreach (T t in childFunction(parent))
{
foreach (T u in Flatten(t, childFunction))
{
yield return u;
}
}
}

To call this method so it pops up a message box containing the names of all the controls on a form (including the form itself) add a method to the form similar to this:
private void button1_Click(object sender, EventArgs e)
{
var controls = Flatten<Control>(this, c => c.Controls.Cast<Control>());
var builder = new StringBuilder();
controls.ForEach(c => builder.AppendLine(c.Name));
MessageBox.Show(builder.ToString());
}

For an explanation of the ForEach method see my previous post.

No comments:

Post a comment