Hiding a non-virtual property for a derived control at design-time

I've recently been developing a custom control (BarControl) that derived from an existing control (FooControl). There were two requirements related to the derived control's border style:

  • The BorderStyle property should not be modified at runtime
  • The BorderStyle property should not be displayed in the Properties pane at design-time

Since the base control exposed a BorderStyle property, I thought I'd need to do three things:

  • override the property
  • change it's access modifier to protected so that only derived classes can access it
  • add a [Browsable(false)] attribute to remove it from Visual Studio's Properties pane

So I blithely whipped out the following code:

 
    [Browsable(false)]
    protected override BorderStyle BorderStyle
    {
        get { return base.BorderStyle; }
        set { base.BorderStyle = value; }
    }
    

The compiler just as blithely hit me with the following error:

 
    Error 1  'BarControl.BorderStyle.get': cannot override inherited member 'FooControl.BorderStyle.get' because it is not marked virtual, abstract, or override
    Error 2  'BarControl.BorderStyle.set': cannot override inherited member 'FooControl.BorderStyle.set' because it is not marked virtual, abstract, or override

Oops! I had expected theĀ BorderStyle property to be virtual and it wasn't. The solution--like most solutions--was obvious once I found it: use the new, rather than the override, modifier to hide the base class property. So I quickly changed the code to:

 
    [Browsable(false)]
    protected new BorderStyle BorderStyle
    {
        get { return base.BorderStyle; }
        set { base.BorderStyle = value; }
    }

Now the compiler was happy, so everything would work as expected, right? I switched to my test app, drug an instance of my control onto a form, and looked for the BorderStyle property in the Properties pane. Lo and behold, it was still there. I was stumped. I had hidden the base property and marked the new property with [Browsable(false)]. What could be wrong?

It took a close reading of the documentation for the new modifier to find the problem: the new modifier overrides members with the same signature. Since the access modifier is part of a member's signature, changing the access modifier from protected to public meant I wasn't hiding the BorderStyle property in the base class. As a result, the BrowsableAttribute was applied to the BorderStyle property in the derived class but not the BorderStyle property in the base class.

What to do. I needed to hide the BorderStyle property at design time, so I needed to make it public in the derived class; however, I also needed to hide the property at runtime so I needed to make it protected. Perhaps, I could apply the protected access modifier to the property's getter and setter methods while still leaving the property access modifier as public. So I tried this:

 
    [Browsable(false)]
    public new BorderStyle BorderStyle
    {
        protected get { return base.BorderStyle; }
        protected set { base.BorderStyle = value; }
    }

The compiler didn't like it:

 
    Error 1  Cannot specify accessibility modifiers for both accessors of the property or indexer 'BarControl.BorderStyle'

Since the goal was to keep the property from being modified at runtime, I settled on the following solution:

 
    [Browsable(false)]
    public new BorderStyle BorderStyle
    {
        get { return base.BorderStyle; }
        protected set { base.BorderStyle = value; }
    }

I'm not sure that there isn't a better solution, but this meets the criteria:

  • The BorderStyle property is not displayed in the Properties pane at design-time
  • The BorderStyle property cannot be modified at runtime

So the three things I actually needed to do were

  • hide the property in the base class with the new modifier
  • change the access modifier of the property's setter method to protected so that only derived classes can access it
  • add a [Browsable(false)] attribute to the derived class property to remove it from Visual Studio's Properties pane

I hope you find this helpful.

Cheers
Dan

Disclaimer: This posting is provided "AS IS" with no warranties, and confers no rights.