Saturday, January 10, 2009

Identifying the Run-Time and the Design Mode

Some logic (like connecting to a database) is not meant to be called when the application is in design mode. Opening a Form, or a UserControl, in the Visual Studio Designer (or other IDE design module), which is trying to connect to a database in its constructor or in its Load or Shown event handler will end up with a Designer exception. Handling a database connection is a run-time job only! This situation may be avoided if the run-time specific code is properly handled.

If you want to execute different code path when the Visual Studio is in Design or Release mode, please read this article: Determine Debug Mode in .NET

Using the DesignMode property

The DesignMode property is stored in the ISite interface and it is a boolean flag which specifies if the current component is in design mode. If the current Form or UserControl we interrogate the DesignMode property for doesn’t have an ISite associated with it, the DesignMode value is always false and the design mode identification will fail.

Also, the DesignMode property doesn’t work as expected for the grandchild controls of a Form or of a complex UserControl, because it returns always false.

Another issue of the DesignMode property is that it doesn't work inside the constructor of a UserControl or Form!

C# .NET

if (this.DesignMode)

{

    // design time only stuff

}

else

{

    // runtime only stuff.

}



Getting the current process name approach

A possible workaround for identifying the design mode is to check the name of the current process which uses the current Form or UserControl. The problem with this approach is that is not IDE independent because each IDE uses different names for its processes. Doesn't work if you don't have premissions to query the process parameters. But it will work inside constructors and event handlers (like the Load event handler).

Bellow is an example of using this approach to identify the design mode if the Visual Studio Designer is used (its process name is: “devenv”). Note this doesn't work in Mono, #Develop, etc.

C# .NET

public new bool DesignMode

{

    get

    {

        return (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv");

    }

}



The LicenceManager and its LicenseModeUsage property

Within the System.ComponentModel namespace is a class called LicenseManager. Its purpose is to help developers to handle licensees for their own UserControls in both the run-time and design mode. For this, it has a handy static function called UsageMode. It returns an enumerated value from LicenseModeUsage with two options:
  • Designtime
  • Runtime
The problem with this class is that it seems to work fine only within constructors (for both Forms and UserControls classes)! If it is used inside an event handler it will return always Runtime!

C# .NET

if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)

{

    // design time only stuff

}

else

{

    // runtime only stuff.

}



Running a test

In order to see how the three approaches can identify the run-time and the design mode, I wrote a small test. I created a WinForm applications containing a UserControl A having inside a UserControl B which also contains a UserControl C. Each of them (including the main Form) pop-ups a message box in the constructor and the Load event handler to describe the state of the three approaches. To complete the test, each of these four components (the three UserControls and the Form) will be open in the Visual Studio Designer to see the pop-ups for design mode and then the application is started to see the pop-ups for the run-time.

Here is my test code I used for each component:

C# .NET

public ucA()

{

    InitializeComponent();

 

    MessageBox.Show("this.DesignMode = " + this.DesignMode.ToString() + "\n\r" +

                    "ProcessName = " + (Process.GetCurrentProcess().ProcessName == "devenv").ToString() + Environment.NewLine +

                    "LicenseManager.UsageMode = " + LicenseManager.UsageMode.ToString(), "User Control A - Constructor");

}

 

private void ucA_Load(object sender, EventArgs e)

{

    MessageBox.Show("this.DesignMode = " + this.DesignMode.ToString() + "\n\r" +

                    "ProcessName = " + (Process.GetCurrentProcess().ProcessName == "devenv").ToString() + Environment.NewLine +

                    "LicenseManager.UsageMode = " + LicenseManager.UsageMode.ToString(), "User Control A - LoadEvent");

}



kick it on DotNetKicks.com

12 comments:

Anonymous said...

I have a related problem. I want to be able to execute code in runtime and in the VisualStudio2005 designer. But it seems, that no code outside of InitializeComponent is executed by the designer, not even the constructor. I have the following simple code :

public Form1( )
{
InitializeComponent( );
Label l = new Label( );
l.Location = new Point( 10, 10 );
l.Size = new Size( 100, 15 );
l.Text = "Text set by program";
this.Controls.Add( l );
}

This shows the label in a runtime environment, but it doesn't show up in designer. I also tried the Load event and various other things. Since your problem is to NOT execute code in designer, I hope you can show a simple example where code IS executed in the designer.

Admin said...

Your problem is caused by the way the VS Designer renders the Form (or any UserControl). It doesn’t execute the constructor at all! In exchange to this, the VS Designer searches for the method called InitializeComponent() and parse it! Not even the InitializeComponent() is executed! Try to rename this method and you will get an empty form.



But this happens only for the root Form or UserControl being visualized in Designer. So if you have a UserControl on a Form and you visualize in Designer the Form, the Form’s InitializeComponent() is parsed and the UserControl’s constructor is executed. In this case, your problem is solved if you move your code into a UserControl and drop it on the Form.




I hope this helps!

Anonymous said...

Thank you for your answer. Unfortunatly, UserControls are no solution for my problem.

Xster said...

Excellent post. Was having problem with this lame issue for a while now

Ross said...

I just wanted to add this as I was trying to figure out a similar problem with the DesignMode property.

I found that you can not check for DesignMode until after the control's handle has been created. Switching my run-time only stuff to checking there fixed all my problems.

Admin said...

Thanks for your tip Ross :)

Anonymous said...

Thanks for the tips.
Presented nicely :]
I ended up using the processname solution.



Bill C.

Vicente Gras said...

Instead of using DesignMode property I use a static bool Running variable that I assign to true in Main() method.

Anonymous said...

Note that while the control/form's constructor isn't called in the designer, the constructor of its BASE class IS called in full. Thus, you may need to put design-time checks in the constructor of a form to make its child classes behave properly, even though the base class itself behaves properly in the designer even without those checks.

Morten

Someone3x7 said...

I ended up using:

public new bool DesignMode
{
get
{
return (System.Diagnostics.Process.GetCurrentProcess().ProcessName == Properties.Settings.Default.ProcessName);
}
}

Anonymous said...

We had a situation where we had a subclassed control that was used on forms and also within a user control embedded on another user control. The following code seems to work in all situations so far:

protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
if (RunTime())
MessageBox.Show("RunTime", (this.Name + ", type: " + this.GetType().Name).Trim());
else
MessageBox.Show("DesignTime", (this.Name + ", type: " + this.GetType().Name).Trim());
}

private bool RunTime()
{
Form parentForm = this.FindForm();
Control parentControl = this.Parent;
// Start with highest level and work down.
if (parentForm != null)
if (parentForm.Site != null && parentForm.Site.DesignMode)
return false;
else
return true;
else if (parentControl != null)
{
if (parentControl.Site != null && parentControl.Site.DesignMode)
return false;
else
return true;
}
else if (this.Site != null && this.Site.DesignMode)
return false;
else
return true;
}

Leo said...

Great article !
Man, you made my day !

Vicente Gras idea is the best solution !