Designing Generic Forms
Did you know that Forms and UserControls can derive from a generic type in .NET 2.0?
For example, you might have a base form like this:
public partial class MyGenericForm<T> : Form
{
/* ... */
}
So this form can be constructed with a type at runtime and its behaviour might differ slightly depending on that type.
Why is that handy? Well, the handiness comes in deriving:
public partial class MyIntForm : MyGenericForm<int>
{
/* ... */
}
Now we have a form that specializes with "int" but inherits all the visual design (and other goodies) from MyGenericForm.
Great in theory, but there's one major catch - doing this means you can't switch to the visual form designer for MyIntForm. Visual Studio just isn't smart enough to construct a visual representation of a form that derives from a generic type.
So are we screwed? Not quite yet!
It's actually possible to fool Visual Studio into thinking that this is a standard, everyday form. You do this by defining a type to sit in between MyGenericForm and MyIntForm:
public class MyCustomIntForm : MyGenericForm<int> { }
So this class does bugger all except derive from MyGenericForm and specialize with the "int" type. Then we adjust our original derived form thusly:
public partial class MyIntForm : MyCustomIntForm
{
/* ... */
}
... and voila! Now we have a form that derives (indirectly) from a generic type, and still works in the visual designer!
This example (using int as the specialized type) is a bit contrived, but I've already found one or two uses for this using my own classes as the type the form is based on. Let me know if it helps you!
Comments
# Jonathan Parker
2/10/2006 8:16 PM
Wow!
That is cool! I just can't get over how much generics makes code reuse easier.
Anyway generics also work with custom controls.
I blogged about a <a href="http://jonathanparker.com.au/JonathanParker/Web/blogs/jonathan/archive/2006/09/26/42.aspx">generic TextBox control</a> a while back.
What's great is being able call methods using different parameter types for converting between dates, times, numbers, strings etc.
I'm disappointed that you can't have generic properties.
I guess that's something that might be in .NET 3.0.
# Eliseu Rodrigues
12/10/2006 10:07 PM
It's a very smart workaround to this problem.
You saved my day.
Thank you.
# Paul Wilson
7/11/2006 2:14 AM
This is a top solution. Thanks
# Eric Stoffer
22/02/2007 3:10 AM
Thanks! that works great ... One other thing, i'm passing a parameter in my constructor so I then have to include the default (no parameters) constructor, which I'd rather not do ... see below
Eric Stoffer
public partial class frmTest : FormBaseTest
{
public frmTest (clsTest test) :base (test)
{
InitializeComponent();
}
...........
}
public class FormBaseTest: FormBase<clsTest>
{
public FormBaseTest(): base()
{
}
public FormBaseTest(clsTest businessObject)
: base(businessObject)
{
}
}
public class FormBase<baseType> : MyControls.FormBase
{
public baseType m_BusinessObject;
public FormBase()
{
}
public FormBase(baseType businessObject)
{
m_BusinessObject = businessObject;
}
}
# mabster
22/02/2007 7:00 AM
Eric,
I could be wrong, but I believe you can make your default constructor private (or protected) so that it's hidden to "users" of your form.
The designer will still be able to use it, since it uses reflection.
Try it out and see if it works.
# Arnaud
18/06/2009 5:23 PM
Hello
I am using your trick , but in the FFBase.designer.cs, the InitializeComponent() method looks for resources :
new System.ComponentModel.ComponentResourceManager( typeof( FFBase<,> ) );
and it "looses" some resources : do you have any idea ?
thanks
# Brian Chavez
16/07/2009 1:43 PM
+1 Thanks, this helped a lot. It's a pain, MS should get this fixed.
# Avo
2/09/2009 5:15 PM
@Arnaud
I faced the same resource problem and i solved it by creating a non-generic dummy form (i.e. inheriting System.Windows.Forms.Form) with the same name as your generic form. In your special case it'd be FFBase: Form.
Hope it helps
# Magnus Tyrland
19/04/2011 8:53 PM
I had the same problem in VS2010 and am very greatful for this tip!
# martan
31/08/2011 5:16 AM
yeah, still not solved in VS 2010 designer, but workaround works..
# drixsee
6/12/2011 3:25 PM
very nice! works for me! :D
# TungTh
15/12/2011 6:17 PM
Very helpful tip. Thank you very much
# PL
17/01/2012 3:53 AM
My generic form does not appear in the Inheritance Picker (Add - New Item - Windows Form - Inherited Form, the list of existing forms to inherit from does not contain my generic form).
# Gabi
29/02/2012 6:33 PM
You are the man!!!!!
Save my time
# António Pena
13/08/2012 11:20 PM
One more happy customer :) It worked Like a charm!
Thanks man ;)
# Hermann
22/03/2013 9:57 PM
Just wanted to thank you for this very useful tip :-)
# Steve B
5/12/2013 6:43 AM
I don't see a need for having all the extra classes? I was able to do this using the normal code behind and designer classes and then adding a dummy class so the ComponentResourceManager call in the designer is happy.
So you have below:
The code behind
public partial class MyGenericForm<T> : Form
{
}
The designer (add the <T>)
partial class MyGenericForm<T>
{
//the normal designer code
//then InitializeComponent autogenerated code will always reference MyGenericForm instead of the MyGenericForm<T> in the call below
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MyGenericForm));
}
}
In order to fake out the designer to fix the ComponentResourceManager reference, create the class below:
class MyGenericForm : Form
{
}
# Steve B
5/12/2013 6:47 AM
I left out the instantiation above.
MyGenericForm<int> frm = new MyGenericForm<int>();
# Ruz
21/03/2016 9:32 PM
Thanks a lot. Great workaround!