Generic control creation.
I've been doing a lot of coding lately that utilize the features of the C# 2.0 and 3.0 language enhancements such as generics, Func delegates, anonymous types etc... And then it hit me that we are still using the old and clumsy coding style when developing for WinForms - creating controls, assinging properties etc... What if we could do something like that:
Button clickButton = this.AddControl<Button>(c => new Button()
{
Name = "button",
Text = "Click Me",
Location = new Point(100, 200),
Font = c.Font
});
In the code above we create an instance of the Button, set it's properties and add it to the parent's controls collection - all in one line of code! Do you like it? I do. Somehow it feels much cleaner and nicer than this:
Button clickButton = new Button();
clickButton.Name = "button";
clickButton.Text = "Click Me";
clickButton.Location = new Point(100, 200);
clickButton.Font = this.Font;
this.Controls.Add(clickButton);
So here is how the code for the "Hello World" sample Form would look like:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Create button and add it to the Form's controls collection
Button clickButton = this.AddControl<Button>(c => new Button()
{
Name = "button",
Text = "Click Me",
Location = new Point(100, 200),
Font = c.Font
});
// Hook up into the click event
clickButton.Click += new EventHandler(clickButton_Click);
// Create label
this.AddControl<Label>(c => new Label()
{
Name = "labelHello",
Location = new Point(100, 240)
});
}
void clickButton_Click(object sender, EventArgs e)
{
// Assign the value to the Text property of the label
this.GetControl<Label>("labelHello").Text = "Hello world.";
}
}
So what do we need to be able to write the code like this? All we need to do is to add the following ControlExtension class:
public static class ControlExtension
{
public static T AddControl<T>(this Control parent,
Func<Control, T> build)
{
T control = build(parent);
parent.Controls.Add(control as Control);
return control;
}
public static Control GetControl(this Control parent, string name)
{
return parent.Controls[name];
}
public static T GetControl<T>(this Control parent, string name)
where T : Control
{
return parent.Controls[name] as T;
}
}
In this class all we do is just create a few extension methods for the Control. That's it folks.
And by the way, this code works on both desktop (.NET 3.5) and device side (.NET CF 3.5)
Enjoy :)
Comments
Anonymous
January 10, 2009
Very neat, especially the AddControl extension! Though I would prefer to leave the controls declaration out of the form’s constructor instead of using the GetControl extension, so the compiler will be able to trace errors and for better performance. Interesting as always. Thx.Anonymous
January 18, 2009
Hi Alex, Great stuff. I ran into a hitch with the Compact Framework with the WinForms implementation not providing a string indexer for Controls, so I used this instead(example from GetControl): return parent.Controls.OfType<Control>().SingleOrDefault(c => c.Name == name); That works OK for me but let me know if there's another approach that's preferred (I'm very partial to LINQ to Objects and likely to use/misuse it whenever an excuse arises).Anonymous
January 21, 2009
Hi Kevin, I would change it like this: return parent.Controls.Cast<Control>().SingleOrDefault(c => c.Name == name); -AlexAnonymous
January 23, 2009
The comment has been removedAnonymous
January 24, 2009
Even though I don't work in the product group, I am pretty sure that Windows Mobile dev is still alive and kicking :)Anonymous
January 26, 2009
Continuing on this mental exercise that I started in my last post . In this post I started throwing someAnonymous
February 16, 2009
Since posting a few of my last ideas , my brain has been running a few background threads on how else