Monday, February 16, 2009

Prevent Visual Studio 2005 Form’s Designer from executing base form behavior.

Have you ever tried to inherit a form and then in Visual Studio Designer you got an error message? Something like this:

InheritedFormError_Example2

or like this:

InheritedFormError_Example1

That is because Visual Studio Designer in order to render base form controls would create an instance of the base form and apparently would try to execute handlers for base form events. If events contain some logic where you call middle tier and connect to a database or make calls that could fail at design time, such as making a request for Principal Permission, this could generate error messages like the ones above, and in turn Designer would not be able to properly render inherited form. 
There are several principles and ways to avoid such behavior.  Don’t forget to recompile your project every time you make changes to base forms. It also helps to close designer window of the inherited form and re open it, that is when new instance of the base form is created and reloaded in the designer.

Basic Principles

Since now we are aware that code on the base form could be executed in the designer we could design our parent class in a way which would avoid such execution.
- In the parameterless constructor for the base (parent) form do not add any logic besides InitializeComponent()
- Or create an overloaded constructor with Protected access modifier, which would be executed only by a child form. 
- Avoid adding logic into Load event of the base form.
- And for that matter avoid adding logic into any event handler for the base form… Don’t you think this is too much? I do.

Ways to prevent base form to execute logic at design time.

There is however a useful property that Form has. It is called DesignMode. You may evaluate this property after instance is created and handle is passed to the Designer. Which means do not check this property in constructor, since it would return false.
If this property evaluates to True than you could stop your code from executing.

Now what if you have multiple base form event handlers and you don’t want to spend time modifying these event handlers by adding this condition. For this purpose there is another neat property on the Form, which is called Events. You could dispose all the events on the form if your base form is in the Designer. So you could add the following code in your base form Load event handler.

Private Sub MyForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    If Me.DesignMode Then
        Me.Events.Dispose()
        Exit Sub
    End If
    '' your logic       

End Sub

So this was another ISolvable problem. :)