How to: Retrieve all controls in a form, using generics (II) – Linq at rescue!


Hi again,

In my previous post, I created a recursive function to retrieve all controls inside a form and its containers. Today, my colleague and friend Eduard Tomàs (software architect @ RAONA) has posted another solution to the same topic based on Linq. It’s quite simply and really, really pretty:

tshirt

A new approach:

Before starting, we need to solve this: Linq works over IEnumerable<T>, but Control.Controls property returns a ControlCollection type. In fact, nowadays, since we have Generics this class has no sense (like other 1.000 similar classes), but remember that Generics doesn’t appeared until .NET Framework 2.0. So, our first step will be retrieve an IEnumerable<Control> from a ControlCollection. With using an extensor method this will be really easy:

public static IEnumerable<Control> AsEnumerable
    (this Control.ControlCollection @this)
{
    foreach (var control in @this)
        yield return (Control)control;
}

Note that using this code we are able to transform CollectionControl to IEnumerable<Control>, and get full access to the power of Linq. Now, let’s create a method to retrieve all controls of a type, as follows:

public static IEnumerable<T>
    GetAllControls<T>(this Control @this) where T : Control
{
    return @this.Controls.AsEnumerable().Where(x => x.GetType() == typeof(T)).
    Select(y=>(T)y).
        Union(@this.Controls.AsEnumerable().
        SelectMany(x => GetAllControls<T>(x)).
        Select(y=>(T)y));
}

It looks cool, isn’t it? No loops, no ifs… only pure Linq power! :-)

There’s a small difference with my original solution and this new one. In my original solution I used an internal List<T> to copy all controls references. The new one only iterates over the original collection. There’s no internal lists. This is the power of Linq.

Another difference present in Linq solution is: We are returning an IEnumerable, so, we loose the ForEach method (because IEnumerable doesn’t implements this method). But building our own ForEach method is trivial:

public static void ForEach<T>
    (this IEnumerable<T> @this, Action<T> action)
{
    foreach (T t in @this)
    {
        action(t);
    }
}

HYEI, happy coding!

November 2010

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s