nwahmaet
nwahmaet

Reputation: 3909

Detecting design mode from a Control's constructor

Following-on from this question, is it possible to detect whether one is in design or runtime mode from within an object's constructor?

I realise that this may not be possible, and that I'll have to change what I want, but for now I'm interested in this specific question.

Upvotes: 121

Views: 84842

Answers (19)

jrlima
jrlima

Reputation: 1

The only way I could get this to work properly was by creating a static var "static bool IsRuntime;". This will have a default "false" value when in design mode. Then in the "main" function I just set it to true. Simple solution that just works.

function MyEvent()
{
  if (MyClass.IsRuntime == false)
  {
     // Design mode!
  }
  else
  {
     // Runtime mode!
  }
}

Main:

[STAThread]
static void Main()
{
  MyClass.IsRuntime = true;
  (...)
}

Upvotes: 0

juFo
juFo

Reputation: 18567

As of .net 6+ you have an additional property IsAncestorSiteInDesignMode.

We have it like this for WinForms .net 6+:

        public static bool IsRealDesignerMode(this Control c)
        {
            return System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime
                || c.IsAncestorSiteInDesignMode
                || System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv";
        }

Upvotes: 0

Barry Smith
Barry Smith

Reputation: 81

Yes, you can check for whether you're in "design mode" from within an object's constructor. But using the WinForms DesignMode property doesn't always work as expected. An alternative:

This is my technique to check DesignMode in C# using Visual Studio and it does work in constructors.

// add this class...
public static class Globals
{
    static Globals() => DesignMode = true;
    public static bool DesignMode { get; set; }
}

// and modify your existing class...
public static class Program
{
    public static void Main()
    {
        Globals.DesignMode = false;
        // ...
        // ... and then the rest of your program
        //
        //  in any of your code you can check Globals.DesignMode for
        //  the information you want.
    }
}

This solution is lightweight and simple. The downside is that you have to remember to clear the flag in your Main code.

When checking for "design mode," we're essentially checking for whether our code is being executed because our whole program is being run or because parts of our code are being executed by the VS designer. With this solution, the flag only gets set to false when the whole program is being run.

Upvotes: 2

Tobias Knauss
Tobias Knauss

Reputation: 3509

Like many others, I have had this problem several times already when designing Windows Forms UserControls.
But today, I had a situation where none of the mentioned solutions worked for me.
The problem is, that LicenseManager.UsageMode only works reliably in the constructor, while DesignMode only works outside the constructor and not always. This is my experience, and this is what is said in a discussion on GitHub.
And another problem comes with inheritance, and embedding user controls in another user controls in another user controls. At the latest in the 2nd level of embedding a user controls, both ways fail!

This can be shown in the UserControls that I created for this test. Every UC has 3 labels:

  1. its (project name) and type name

  2. The values of

    • DesignMode (true: "DM=1"),
    • LicenseManager.UsageMode == LicenseUsageMode.Designtime, queried locally, (true: "local_LM-DT=1")
    • LicenseManager.UsageMode == LicenseUsageMode.Designtime, queried from a private field that was written in the constructor (true: "ctor_LM-DT=1")

    all taken inside the constructor ("CTOR") and inside a method that was called from the constructor ("CFCtor")

  3. The same values as in 2)
    all taken inside the Load event ("Load()") and inside a method that was called from the Load event ("CFLoad")

The UserControls and the Form that I created are (all screenshots shown them in the WinForms Designer):

  • UserControl1:

    • contains 3 labels

    enter image description here
    The Designer does not execute the construtor or events, therefore the labels are not filled.

  • UserControl1a:

    • inherits from UserControl1
    • contains 2 more labels

    enter image description here
    The Designer executes the construtor and events of the parent UserControl.

  • UserControl2: contains

    • contains 3 labels
    • contains 1 UserControl1
    • contains 1 UserControl1a

    enter image description here
    The Designer executes the construtors and events of the embedded UserControls.
    Only 1 level of embedding.

  • UserControl3:

    • contains 3 labels
    • contains 1 UserControl2

    enter image description here
    The Designer executes the construtors and events of the embedded UserControls.
    2 level of embedding: The values inside the UserControl at 2nd embedding level are wrong.

  • Form1:

    • contains 3 labels
    • contains 1 UserControl1
    • contains 1 UserControl1a
    • contains 1 UserControl2
    • contains 1 UserControl3.

    enter image description here The Designer executes the construtors and events of the embedded UserControls.
    3 level of embedding: The values inside the UserControl at 2nd and 3rd embedding level are wrong.

As you can see from the screenshots, "ctor_LM-DT" is always 1.
This means, that storing the value from the LicenseManager in a member field is necessary to get a valid status of the Designer usage:

private LicenseUsageMode m_ctorLMUsageMode = LicenseManager.UsageMode;

For the sake of completeness, here's some of my code that can be used to reproduce the test:

public static string CreateText(bool i_isInDesignMode, LicenseUsageMode i_localLicenseUsageMode, LicenseUsageMode i_ctorLicenseUsageMode)
{
  return $"DM={(i_isInDesignMode ? 1 : 0)} local_LM-DT={(i_localLicenseUsageMode == LicenseUsageMode.Designtime ? 1 : 0)} ctor_LM-DT={(i_ctorLicenseUsageMode == LicenseUsageMode.Designtime ? 1 : 0)}";
}

The other UserControls are identical or similar:

public partial class UserControl1 : UserControl
{
  private LicenseUsageMode m_ctorLMUsageMode = LicenseManager.UsageMode;

  public UserControl1()
  {
    InitializeComponent();

    label2.Text = $"CTOR: {CInitTester.CreateText (DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
    CalledFromCtor();
  }

  private void UserControl1_Load(object sender, EventArgs e)
  {
    label3.Text = $"Load(): {CInitTester.CreateText(DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
    CalledFromLoad();
  }

  private void CalledFromCtor()
  {
    label2.Text += $"\r\nCFCtor: {CInitTester.CreateText (DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
  }

  private void CalledFromLoad()
  {
    label3.Text += $"\r\nCFLoad: {CInitTester.CreateText (DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
  }
}

Upvotes: 4

Karl bauer
Karl bauer

Reputation: 31

I wasn't able to get any of these solutions to work for me in Visual Studio 2019 when creating a WinForms app on .NET Core 3.1.

Both Appllication.ProcessName and Process.ProcessName are returning "DesignToolsServer" for me and LicenseManager.UsageMode returns LicenseUsageMode.Runtime when the Control is in another control or just on a form itself.

I did get it to work using Application.ProcessName == "DesignToolsServer".

Upvotes: 3

Don P
Don P

Reputation: 539

Timers that are enabled by default can cause crash when using custom/user controls. Disable them by default, and enable only after design mode check

   public chartAdapter()
    {
        try
        {

            //Initialize components come here
            InitializeComponent();

            //Design mode check
            bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
            if (designMode)
                return;

            //Enable timers ONLY after designmode check, or else crash
            timerAutoConnect.Enabled = timerDraw.Enabled = true;

Upvotes: 0

Derek Tremblay
Derek Tremblay

Reputation: 197

You can use this

if (DesignerProperties.GetIsInDesignMode(this))
{
...
}

Upvotes: 4

    private void CtrlSearcher_Load(object sender, EventArgs e)
    {
           if(!this.DesignMode) InitCombos();
    }

Upvotes: 0

qaqz111
qaqz111

Reputation: 191

This is the method I used in my project:

//use a Property or Field for keeping the info to avoid runtime computation
public static bool NotInDesignMode { get; } = IsNotInDesignMode();
private static bool IsNotInDesignMode()
{
    /*
    File.WriteAllLines(@"D:\1.log", new[]
    {
        LicenseManager.UsageMode.ToString(), //not always reliable, e.g. WPF app in Blend this will return RunTime
        Process.GetCurrentProcess().ProcessName, //filename without extension
        Process.GetCurrentProcess().MainModule.FileName, //full path
        Process.GetCurrentProcess().MainModule.ModuleName, //filename
        Assembly.GetEntryAssembly()?.Location, //null for WinForms app in VS IDE
        Assembly.GetEntryAssembly()?.ToString(), //null for WinForms app in VS IDE
        Assembly.GetExecutingAssembly().Location, //always return your project's output assembly info
        Assembly.GetExecutingAssembly().ToString(), //always return your project's output assembly info
    });
    //*/

    //LicenseManager.UsageMode will return RunTime if LicenseManager.context is not present.
    //So you can not return true by judging it's value is RunTime.
    if (LicenseUsageMode.Designtime == LicenseManager.UsageMode) return false;
    var procName = Process.GetCurrentProcess().ProcessName.ToLower();
    return "devenv" != procName //WinForms app in VS IDE
        && "xdesproc" != procName //WPF app in VS IDE/Blend
        && "blend" != procName //WinForms app in Blend
        //other IDE's process name if you detected by log from above
        ;
}

Attention!!!: The code returned bool is indicating NOT in design mode!

Upvotes: 2

Giovanny Farto M.
Giovanny Farto M.

Reputation: 1588

If you want to run some lines when it is running but not in the Visual Studio designer, you should implement the DesignMode property as follows:

// this code is in the Load of my UserControl
if (this.DesignMode == false)
{
    // This will only run in run time, not in the designer.
    this.getUserTypes();
    this.getWarehouses();
    this.getCompanies();
}

Upvotes: 0

Vaclav Svara
Vaclav Svara

Reputation: 359

Component ... as far as I know does not have the DesignMode property. This property is provided by Control. But the problem is when CustomControl is located in a Form in the designer, this CustomControl is running in runtime mode.

I have experienced that the DesignMode property works correct only in Form.

Upvotes: 11

Vaclav Svara
Vaclav Svara

Reputation: 59

With cooperation of the designer... It can be used in Controls, Components, in all places

    private bool getDesignMode()
    {
        IDesignerHost host;
        if (Site != null)
        {
            host = Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (host != null)
            {
                if (host.RootComponent.Site.DesignMode) MessageBox.Show("Design Mode");
                else MessageBox.Show("Runtime Mode");
                return host.RootComponent.Site.DesignMode;
            }
        }
        MessageBox.Show("Runtime Mode");
        return false;
    }

MessageBox.Show( lines should be removed. It only makes me sure it works correctly.

Upvotes: 3

Beauty
Beauty

Reputation: 965

IMPORTANT

There is a difference of using Windows Forms or WPF!!

They have different designers and and need different checks. Additionally it's tricky when you mix Forms and WPF controls. (e.g. WPF controls inside of a Forms window)

If you have Windows Forms only, use this:

Boolean isInWpfDesignerMode   = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);

If you have WPF only, use this check:

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

If you have mixed usage of Forms and WPF, use a check like this:

Boolean isInWpfDesignerMode   = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
Boolean isInFormsDesignerMode = (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv");

if (isInWpfDesignerMode || isInFormsDesignerMode)
{
    // is in any designer mode
}
else
{
    // not in designer mode
}

To see the current mode you can show a MessageBox for debugging:

// show current mode
MessageBox.Show(String.Format("DESIGNER CHECK:  WPF = {0}   Forms = {1}", isInWpfDesignerMode, isInFormsDesignerMode));

Remark:

You need to add the namespaces System.ComponentModel and System.Diagnostics.

Upvotes: 8

Rob
Rob

Reputation: 1777

The LicenseManager solution does not work inside OnPaint, neither does this.DesignMode. I resorted to the same solution as @Jarek.

Here's the cached version:

    private static bool? isDesignMode;
    private static bool IsDesignMode()
    {
        if (isDesignMode == null)
            isDesignMode = (Process.GetCurrentProcess().ProcessName.ToLower().Contains("devenv"));

        return isDesignMode.Value;
    }

Be aware this will fail if you're using any third party IDE or if Microsoft (or your end-user) decide to change the name of the VS executable to something other than 'devenv'. The failure rate will be very low, just make sure you deal with any resulting errors that might occur in the code that fails as a result of this and you'll be fine.

Upvotes: 0

formatc
formatc

Reputation: 4323

Controls(Forms, UserControls etc.) inherit Component class which has bool property DesignMode so:

if(DesignMode)
{
  //If in design mode
}

Upvotes: 10

user492238
user492238

Reputation: 4084

Another interesting method is described on that blog: http://www.undermyhat.org/blog/2009/07/in-depth-a-definitive-guide-to-net-user-controls-usage-mode-designmode-or-usermode/

Basically, it tests for the executing assembly being statically referenced from the entry assembly. It circumvents the need to track assembly names ('devenv.exe', 'monodevelop.exe'..).

However, it does not work in all other scenarios, where the assembly is dynamically loaded (VSTO being one example).

Upvotes: 2

adrianbanks
adrianbanks

Reputation: 82944

You can use the LicenceUsageMode enumeration in the System.ComponentModel namespace:

bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);

Upvotes: 223

Ula Krukar
Ula Krukar

Reputation: 12999

You should use Component.DesignMode property. As far as I know, this shouldn't be used from a constructor.

Upvotes: 5

Jarek
Jarek

Reputation: 5935

Are you looking for something like this:

public static bool IsInDesignMode()
{
    if (Application.ExecutablePath.IndexOf("devenv.exe", StringComparison.OrdinalIgnoreCase) > -1)
    {
        return true;
    }
    return false;
}

You can also do it by checking process name:

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

Upvotes: 27

Related Questions