views:

1016

answers:

10

Has anyone found a useful solution to the DesignMode problem when developing controls?

The issue is that if you nest controls then DesignMode only works for the first level. The second and lower levels DesignMode will always return FALSE.

The standard hack has been to look at the name of the process that is running and if it is "DevEnv.EXE" then it must be studio thus DesignMode is really TRUE.

The problem with that is looking for the ProcessName works its way around through the registry and other strange parts with the end result that the user might not have the required rights to see the process name. In addition this strange route is very slow. So we have had to pile additional hacks to use a singleton and if an error is thrown when asking for the process name then assume that DesignMode is FALSE.

A nice clean way to determine DesignMode is in order. Acually getting Microsoft to fix it internally to the framework would be even better!

+2  A: 

I've never been caught by this myself, but couldn't you just walk back up the Parent chain from the control to see if DesignMode is set anywhere above you?

Will Dean
+1  A: 

DesignMode is a private property (from what I can tell). The answer is to provide a public property that exposes the DesignMode prop. Then you can cascasde back up the chain of user controls until you run into a non-user control or a control that is in design mode. Something like this....

  public bool RealDesignMode()
  {
     if (Parent is MyBaseUserControl)
     {
        return (DesignMode ? true : (MyBaseUserControl) Parent.RealDesignMode;
     }

     return DesignMode;
  }

Where all your UserControls inherit from MyBaseUserControl. Alternatively you could implement an interface that exposes the "RealDeisgnMode".

Please note this code is not live code, just off the cuff musings. :)

Craig
+1  A: 

I hadn't realised that you can't call Parent.DesignMode (and I have learned something about 'protected' in C# too...)

Here's a reflective version: (I suspect there might be a performance advantage to making designModeProperty a static field)

static bool IsDesignMode(Control control)
{
    PropertyInfo designModeProperty = typeof(Component).
      GetProperty("DesignMode", BindingFlags.Instance | BindingFlags.NonPublic);

    while (designModeProperty != null && control != null)
    {
        if((bool)designModeProperty.GetValue(control, null))
        {
            return true;
        }
        control = control.Parent;
    }
    return false;
}
Will Dean
+10  A: 

Why don't you check LicenseManager.UsageMode. This property can have the values LicenseUsageMode.Runtime or LicenseUsageMode.Designtime.

Is you want code to only run in runtime, use the following code:

if (LicenseManager.UsageMode == LicenseUsageMode.Runtime)
{
  bla bla bla...
}
hopla
+1 I've used this too. What trips people up is that DesignMode won't work in a constructor.
Nicholas Piasecki
+7  A: 

Elsewhere I have also seen this solution:

call GetService(typeof(IDesignerHost)) and see if it returns something

To try and get a hang on the three solutions proposed, I created a little test solution - with three projects: TestApp (winforms application), SubControl (dll) and SubSubControl (dll)

I then embedded the SubSubControl in the SubControl, then one of each in the TestApp.Form.

This screenshot shows the result when running.

Screenshot of running

This screenshot shows the result with the form open in Visual Studio:

Screenshot of not running

Conclusion: It would appear that the only one that is reliable within the constructor is LicenseUsage, and the only one which is reliable outside the constructor is 'IsDesignedHosted' (by BlueRaja below)

Benjol
@Benjol: What about IsDesignerHosted (below)? (Also, I think you have design-time and runtime swapped, check what it says during runtime)
BlueRaja - Danny Pflughoeft
@BlueRaja, I must still have that project lying around somewhere on disk, maybe I should post it somewhere...
Benjol
@BlueRaja, I've added your property to the test, and uploaded new screenshots.
Benjol
+2  A: 

From this page:

/// <summary>
/// The DesignMode property does not correctly tell you if
/// you are in design mode.  IsDesignerHosted is a corrected
/// version of that property.
/// (see https://connect.microsoft.com/VisualStudio/feedback/details/553305
/// and http://decav.com/blogs/andre/archive/2007/04/18/1078.aspx )
/// </summary>
public bool IsDesignerHosted
{
    get
    {
        Control ctrl = this;

        while (ctrl != null)
        {
            if ((ctrl.Site != null) && ctrl.Site.DesignMode)
                return true;
            ctrl = ctrl.Parent;
        }
        return false;
    }
}

I've submitted a bug-report with Microsoft; I doubt it will go anywhere, but vote it up anyways, as this is obviously a bug (whether or not it's "by design").

BlueRaja - Danny Pflughoeft
A: 

I use the LicenseManager method, but cache the value from the constructor for use throughout the lifetime of the instance.

public MyUserControl()
{
    InitializeComponent();
    m_IsInDesignMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
}

private bool m_IsInDesignMode = true;
public bool IsInDesignMode { get { return m_IsInDesignMode; } }
Jonathan
A: 

+1 to Hopla's LicenseManager solution - it also works on base controls being constructed during design of a derived control.

mcw0933
A: 

This is the method I use inside forms:

    /// <summary>
    /// Gets a value indicating whether this instance is in design mode.
    /// </summary>
    /// <value>
    ///     <c>true</c> if this instance is in design mode; otherwise, <c>false</c>.
    /// </value>
    protected bool IsDesignMode
    {
        get { return DesignMode || LicenseManager.UsageMode == LicenseUsageMode.Designtime; }
    }

This way, the result will be correct, even if either of DesignMode or LicenseManager properties fail.

husayt