in

Platinum Bay

Peace, Love, and...

This Blog

Syndication


.NETicated

Designing Windows Forms with Abstract Inheritance

I got sick of Notepad a couple weeks ago, and set about to build a Notepad-like application with a couple sorely missing features like reload prompting, multiple undo levels, tabs, line numbers, more robust find and replace, recent files list, opacity, etc. It's a cool little project, titled DevNotepad, and is currently about 3,000 lines of code. It's fast too, which is very important for a Notepad replacement. The beauty of Notepad itself is its compact size and loading speed. More on DevNotepad later.

Along the way though, I ran into a problem trying to visually design user controls which inherited from an abstract class. Out of the install (box), Visual Studio does not support this. If you were to try and visually design a form which inherits from an abstract class, you would get a message similar to the following:

After digging through [your favorite search engine], I found it is possible to modify this behavior. The key is to provide a TypeDescriptionProvider attribute to the base abstract class:

[TypeDescriptionProvider(typeof(SubstituteBaseUserControlProvider))]
public abstract class BaseUserControl : UserControl
...

If you don't have Reflector installed, TypeDescriptorProvider is in the System.ComponentModel namespace. The next step is to build the actual provider itself:

internal class ReplaceOptionsPageProvider : TypeDescriptionProvider

   
public ReplaceOptionsPageProvider()
       
: base(TypeDescriptor.GetProvider(typeof(BaseOptionsPage)))
   
{
    }

    public override Type GetReflectionType(Type objectType, object instance)
   
{
       
if (objectType == typeof (BaseOptionsPage))
           
return typeof (ReplaceForm);

       
return base.GetReflectionType(objectType, instance);
   
}

   
public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
   
{
       
if (objectType == typeof (BaseOptionsPage))
           
objectType = typeof (ReplaceForm);

        return base.CreateInstance(provider, objectType, argTypes, args);
   
}
}

The above code detects if the user control to be designed inherits from the aforementioned abstract class, and gives it a replacement to start designing from – a stand-in base class. Therefore, the final step is to build the stand-in user control, inheriting from the original abstract class:

internal class StandInUserControl : BaseOptionsPage

Once the code is in place, close any open designer windows, rebuild the project, and re-open the previously troublesome designer. You should be good to go.

Hope this helps

Comments

February 13, 2009 1:51 AM

It works but fine ...

The same code in VB.NET doesn't works. The "declared as abstract" error persists...

Thanks anyway!

David
 

May 2, 2009 11:39 PM

Where can I get that Reflector?

SubstituteBaseUserControlProvider ?

alon.

alon
 

May 3, 2009 8:20 PM

Alon:

You can download Red-Gate's .NET Reflector here:

www.red-gate.com/.../reflector

SubstituteBaseUserControlProvider is simply the base abstract class that you want your User Controls to inherit from.

Hope this helps

 

August 27, 2009 2:21 AM

Seems I'm not educated enough to understand.

I derive an abstract MyTabPage from a standard TabPage (MSVS 2008/C#3.5SP1)

so in your example i replaced:

BaseOptionsPage --> TabPage

ReplaceForm --> MyTabPage

the line: internal class StandInUserControl : BaseOptionsPage

i assume that this has to have an empty body:

internal class StandInUserControl : TabPage

{

}

then over my abstract class:

[TypeDescriptionProvider(typeof(StandInUserControl))]

public abstract /*partial*/ class TabMsg : TabPage

{

  ...(all needed programming)

}

Still the same happens

Marcel
 

August 27, 2009 5:12 AM

I tried the same but then from a UserControl, but the result is similar.

In your example there are a lot of names. are they matching in the whole example?

Marcel
 

December 20, 2009 7:26 PM

Nice one Steve

But I think you have the names mixed up, as the others have suggested.

- ReplaceOptionsPageProvider should be SubstituteBaseUserControlProvider.  When using Steve's code, you can rename this to what you like.

- BaseOptionsPage should be BaseUserControl.  When using Steve's code, replace this with the name of your abstract base class.

- ReplaceForm should be StandInUserControl.  When using Steve's code, replace this with the concrete version of BaseUserControl to use when designing.  Or set to UserControl (for speed, or when your abstract control affects internal behaviour rather than visible behaviour).

AdamS
 

February 25, 2010 8:35 AM

unfortunately this won't work in VS 2008

Eugene
 

July 27, 2010 9:15 PM

There is a better solution here:  stackoverflow.com/.../2406058

Lucas
 

April 1, 2011 8:40 AM

Hello. Software you are developing probably already exists. Its name is PsPad and I use it a lot:

http://www.pspad.com/en/

Racky
 

June 13, 2011 7:37 AM

Thanks a lot Steve.

I am using VS 2008 and your idea worked perfectly in my case. Like Adam said, your code was a bit confusing so I am giving here my simple version that does the same thing.

   public class AbstractCommunicatorProvider :  TypeDescriptionProvider

   {

       public AbstractCommunicatorProvider() : base(TypeDescriptor.GetProvider(typeof(UserControl)))

       {

       }

       public override Type GetReflectionType(Type objectType, object instance)

       {

           return typeof(UserControl);

       }

       public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)

       {

           objectType = typeof(UserControl);

           return base.CreateInstance(provider, objectType, argTypes, args);

       }

   }

Imran
 

August 26, 2011 9:23 AM

Also works in VB.NET (VS 2008 Express):

Partial Class UserControl1

   Inherits Class1

....

Friend Class SubstituteBaseUserControlProvider

   Inherits TypeDescriptionProvider

   Public Sub New()

       MyBase.New(TypeDescriptor.GetProvider(GetType(UserControl)))

   End Sub

   Public Overrides Function GetReflectionType(ByVal objectType As Type, ByVal instance As Object) As Type

       If objectType Is GetType(Class1) Then

           Return GetType(UserControl)

       End If

       Return MyBase.GetReflectionType(objectType, instance)

   End Function

   Public Overrides Function CreateInstance(ByVal provider As IServiceProvider, ByVal objectType As Type, ByVal argTypes As Type(), ByVal args As Object()) As Object

       If objectType Is GetType(Class1) Then

           objectType = GetType(UserControl)

       End If

       Return MyBase.CreateInstance(provider, objectType, argTypes, args)

   End Function

End Class

<TypeDescriptionProvider(GetType(SubstituteBaseUserControlProvider))> _

Public MustInherit Class Class1

   Inherits UserControl

End Class

Greg Drazek
 

September 24, 2011 3:38 AM

Can it be implement for Window form also ?

Emmanuel
 

Leave a Comment

(required )  
(optional )
(required )  
Add

About Steve

Steve Andrews is an independent consultant, INETA speaker, and Microsoft MVP for Visual Studio ALM. He has been working in technology for over ten years focusing on custom application development and Application Lifecycle Management. Steve is also Microsoft and IBM certified and a community fanatic having led sessions at nearly 100 events across North America. When he's not developing software solutions or engaging with the community about software technology, Steve is a closet singer and songwriter and plays the guitar and keys. Occasionally, Steve even gets to sleep. Occasionally.
Powered by Community Server (Commercial Edition), by Telligent Systems
© Platinum Bay | Some Rights Reserved Creative Commons License

Disclaimer: The information in this weblog is provided "AS IS" with no warranties, and confers no rights. This weblog does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion. Feel free to challenge me, disagree with me, or tell me I'm completely nuts in the comments section of each blog entry, but I reserve the right to delete any comment for any reason whatsoever (abusive, profane, rude, or annonymous comments) - so keep it polite, please.