Click here to Skip to main content
15,879,474 members
Articles / Programming Languages / C#
Tip/Trick

Deriving a concrete class from an abstract UserControl

Rate me:
Please Sign up or sign in to vote.
4.83/5 (3 votes)
29 Oct 2013CPOL3 min read 17K   5  
Abstract base classes are a very good idea - but when that base class is a UserControl, Visual studio gets very unfriendly. It is possible, and it's not difficult: you just have to know how to do it.

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:

  1. How do you create a class derived from a UserControl anyway? What do you use?
  2. 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: 
  • C#
    public partial class MyDerivedControlClass : Control 
  • Replace the Control with the name of your base UserControl class 
  • C#
    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:  
  • C#
    /// <summary>
    /// This class exists solely to provide a non-abstract layer
    /// </summary>
    [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:

C#
[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: 

C#
#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: 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO
Wales Wales
Born at an early age, he grew older. At the same time, his hair grew longer, and was tied up behind his head.
Has problems spelling the word "the".
Invented the portable cat-flap.
Currently, has not died yet. Or has he?

Comments and Discussions

 
-- There are no messages in this forum --