Detectando el modo de diseño del constructor de un Control

99

Siguiendo con esta pregunta , ¿es posible detectar si uno está en modo de diseño o en tiempo de ejecución desde dentro del constructor de un objeto?

Me doy cuenta de que puede que esto no sea posible y que tendré que cambiar lo que quiero, pero por ahora me interesa esta pregunta específica.

nwahmaet
fuente

Respuestas:

192

Puede usar la enumeración LicenceUsageMode en el System.ComponentModelespacio de nombres:

bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
adrianbanks
fuente
2
Solución elegante, funciona mejor que la funcionalidad de C # ISite.DesignMode.
56ka
10
@Filip Kunc: si esto no funciona en OnPaint, puede verificar esta condición en el constructor y almacenarla en un campo de clase.
IMil
3
Esto tampoco funciona cuando se reemplaza WndProc en un control de usuario. Tiene que usar la sugerencia de @IMil
Matt Skeldon
1
ponerlo en la construcción es una buena idea IMil, funcionó para mí ... Traté de ponerlo en un campo de clases estáticas, pero (creo que) los campos de clases estáticas se inicializaron cuando los llamaste por primera vez, así que no es una solución segura ...
Ibrahim Ozdemir
22

Estás buscando algo así:

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

También puede hacerlo comprobando el nombre del proceso:

if (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv")
   return true;
Jarek
fuente
4
Funciona en OnPaint, clases derivadas, constructores, etc. La mejor solución hasta ahora.
Filip Kunc
14
En mi humilde opinión, esto parece una fea solución.
Camilo Martin
5
Atención posible fuga de memoria aquí. El proceso debe eliminarse.
finalmente
7
Si bien estoy seguro de que esto funcionará bien en la mayoría de los casos de uso, esta solución tiene un defecto principal: Visual Studio no es (al menos en teoría) el único host de diseño. Por lo tanto, esta solución solo funcionará si su diseñador está alojado en una aplicación llamada devenv.
stakx - ya no contribuye
2
Funciona en VS2013, a diferencia de la respuesta actualmente aceptada.
Moby Disk
9

Componente ... que yo sepa no tiene la propiedad DesignMode. Esta propiedad es proporcionada por Control. Pero el problema es que cuando CustomControl se encuentra en un formulario en el diseñador, este CustomControl se ejecuta en modo de tiempo de ejecución.

He experimentado que la propiedad DesignMode funciona correctamente solo en Form.

Vaclav Svara
fuente
¡Gracias por el consejo! Nunca me había dado cuenta de eso antes, pero tiene perfecto sentido. El uso del método LicenseManager proporcionado por adrianbanks funciona perfectamente en estos casos, donde el control está incrustado en otro control / formulario. +1 por cada uno!
Josh Stribling
1
+1 Tienes toda la razón, esta también ha sido mi experiencia. Cuando coloca un control de usuario en un formulario, si hay eventos de mouseenter o de carga, DesignMode seguirá apareciendo como falso porque no está en modo de diseño para este control. En mi experiencia, hace que Visual Studio se bloquee con bastante fuerza.
Kyle B
8

Los controles (formularios, controles de usuario, etc.) heredan lo Component classque tiene bool property DesignMode:

if(DesignMode)
{
  //If in design mode
}
formatoc
fuente
4
Que no se establece cuando se ejecuta el constructor, también conocido como el problema inicial del OP. El primer momento en que puedes usarlo es en OnHandleCreated.
Ray
8

IMPORTANTE

¡Hay una diferencia entre usar Windows Forms o WPF !

Tienen diferentes diseñadores y necesitan diferentes controles . Además, es complicado mezclar formularios y controles WPF. (por ejemplo, controles WPF dentro de una ventana de formularios)

Si solo tiene Windows Forms , use esto:

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

Si solo tiene WPF , use esta verificación:

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

Si tiene un uso mixto de Formularios y WPF, use una marca como esta:

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
}

Para ver el modo actual, puede mostrar un cuadro de mensaje para depurar:

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

Observación:

Debe agregar los espacios de nombres System.ComponentModel y System.Diagnostics .

Belleza
fuente
Creo que tu nombre es engañoso. Cuando se usa para WinForms, el nombre es 'isInWpfDesignerMode' y para WPF es 'isInFormsDesignerMode'
M Stoerzel
5

Debe usar la propiedad Component.DesignMode. Hasta donde yo sé, esto no debería usarse desde un constructor.

Ula Krukar
fuente
7
Esto no funciona cuando su control está dentro de otro control o formulario que se está diseñando.
Eric
1
En realidad, funciona bastante bien en mis componentes. Siempre tuve que agregar if (!DesignMode)a los métodos de OnPaint para asegurarme de que no sea spam el tiempo de diseño.
Bitterblue
4

Otro método interesante se describe en ese blog: http://www.undermyhat.org/blog/2009/07/in-depth-a-definitive-guide-to-net-user-controls-usage-mode-designmode-or -modo de usuario/

Básicamente, prueba que el ensamblado en ejecución se haga referencia estáticamente desde el ensamblado de entrada. Evita la necesidad de realizar un seguimiento de los nombres de ensamblados ('devenv.exe', 'monodevelop.exe' ..).

Sin embargo, no funciona en todos los demás escenarios, donde el ensamblado se carga dinámicamente (VSTO es un ejemplo).

user492238
fuente
El vínculo está (efectivamente) roto. Ahora redirige a la última publicación del blog (actualmente 2016-03).
Peter Mortensen
3

Con la cooperación del diseñador ... Se puede utilizar en controles, componentes, en todos los lugares

    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(las líneas deben eliminarse. Solo me asegura que funciona correctamente.

Vaclav Svara
fuente
3

Puedes usar esto

if (DesignerProperties.GetIsInDesignMode(this))
{
...
}
Derek Tremblay
fuente
Esta respuesta es para WPF, la pregunta es sobre WinForms.
Rhys Jones
1

Este es el método que utilicé en mi proyecto:

//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
        ;
}

¡¡¡Atención !!!: ¡ El código devuelto bool indica que NO está en modo de diseño!

qaqz111
fuente
1
    private void CtrlSearcher_Load(object sender, EventArgs e)
    {
           if(!this.DesignMode) InitCombos();
    }
Ángel Ibáñez
fuente
Si bien este código puede responder a la pregunta, proporcionar un contexto adicional sobre cómo y / o por qué resuelve el problema mejoraría el valor de la respuesta a largo plazo.
Tiago Martins Peres 李大仁
0

La solución LicenseManager no funciona dentro de OnPaint, ni tampoco this.DesignMode. Recurrí a la misma solución que @Jarek.

Aquí está la versión en caché:

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

        return isDesignMode.Value;
    }

Tenga en cuenta que esto fallará si está utilizando un IDE de terceros o si Microsoft (o su usuario final) decide cambiar el nombre del ejecutable VS a otro que no sea 'devenv'. La tasa de fallas será muy baja, solo asegúrese de lidiar con cualquier error resultante que pueda ocurrir en el código que falla como resultado de esto y estará bien.

Robar
fuente
0

Si desea ejecutar algunas líneas cuando se está ejecutando pero no en el diseñador de Visual Studio, debe implementar la propiedad DesignMode de la siguiente manera:

// 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();
}
Giovanny Farto M.
fuente
0

Los temporizadores que están habilitados de forma predeterminada pueden causar fallas al usar controles personalizados / de usuario. Deshabilítelos de forma predeterminada y habilítelos solo después de verificar el modo de diseño

   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;
Ayson Baxter
fuente