Introduction
Creating an abstract class is very useful - it allows us to have an base class that contains all the common code but which cannot be instantiated: we all know this. But...when that base class is a UserControl, there are two problems:
- How do you create a class derived from a UserControl anyway? What do you use?
- Why does Visual Studio complain that it can't display my derived class because it isn't based on a concrete class? And what can I do about it - I need to see the thing to add controls!
This Tip shows you how.
Background
Some of this is included in an article I wrote a while ago: A multi-selection Drop Down List using a generic Abstract PopUp class[^] but I went looking for the information today and it wasn't obvious where it was, so I decided to include it in a more specific Tip to make it easier to find.
Deriving from a UserControl (the easy bit)
This is actually pretty easy - but even from a concrete base class it's not obvious exactly what to do. What class do you use to base the derived class on when you add it to the project? UserControl doesn't work - it give all sorts of errors and needs a good amount of cleaning before it works.
Solution:
- Create your base class, derived from UserControl in the normal way.
- Right click your project, and select "Add...New Item"
- From the dialog, select "Custom Control" and give it an appropriate name
- Press OK.
- When the control has been created, go to the definition line:
public partial class MyDerivedControlClass : Control
Replace the Control with the name of your base UserControl class
public partial class MyDerivedControlClass : MyBaseControlClass
Check the code itself: it will have created an OnPaint handler which you probably don't need. It doesn't hurt to leave it there, but if you don't need to use it, you probably should remove it.
Done!
Deriving from an abstract UserControl (the annoying bit)
Surprisingly, this isn't difficult - it's actually pretty easy. But...if you don't do something then Visual studio will complain and refuse to show your derived control in the designer. This means you can't add controls easily, move anything, see what you have, access the properties...do anything useful in fact.
Why? Because Visual Studio will not display controls derived from an abstract class (and has done since at least VS2008). It will however display controls derived from controls derived from an abstract class. Even if the intermediate control contains nothing at all...
So... a bodge!
- Edit your abstract base control class, and go to the end of the file.
- Just inside the namespace, but outside the definition of your UserControl, add these lines:
[ToolboxItem(false)] public class IntermediateMyAbstractBaseControl : MyAbstractBaseControl<mycontrol> { }
Obviously, replace MyAbstractBaseControl
with the name of your abstract base control class.Now, derive your concrete control class from IntermediateMyAbstractBaseControl
and it'll all work fine. The ToolboxItem
attribute means that the intermediate class does not show up in the Visual Studio toolbox. You will probably want to add:
[ToolboxItem(true)]
To your concrete class declaration in order to get it back into the toolbox for the designer.
Now, you want to tell me why the Visual Studio designer doesn't do that internally? :laugh:
You can do much the same thing without the intermediate class intruding so much in class diagrams by using #if DEBUG
around the class definition:
#if DEBUG
public partial class MyDerivedControl : IntermediateMyAbstractBaseControl
#else
public partial class MyDerivedControl : MyAbstractBaseControl
#endif
And similarly around the declaration of the intermediate class to remove it from production code.
But I don't like that approach as it means that the version of code you are testing against is not the same as the version you are releasing - so full functional testing on the release version as a must!
History
- Original version
- 29 Oct 2013: Added
ToolboxItem
part to get the derived control back. :doh: