Détection du mode de conception depuis le constructeur d'un contrôle


99

À la suite de cette question , est-il possible de détecter si l'on est en mode conception ou en mode exécution depuis le constructeur d'un objet?

Je me rends compte que ce n'est peut-être pas possible et que je vais devoir changer ce que je veux, mais pour l'instant je m'intéresse à cette question précise.

Réponses:


193

Vous pouvez utiliser l' énumération LicenceUsageMode dans l' System.ComponentModelespace de noms:

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

2
Solution élégante, elle fonctionne mieux que la fonctionnalité C # ISite.DesignMode.
56ka

10
@Filip Kunc: si cela ne fonctionne pas dans OnPaint, vous pouvez vérifier cette condition dans le constructeur et la stocker dans un champ de classe.
IMil

3
Cela ne fonctionne pas non plus lors de la substitution de WndProc dans un contrôle utilisateur. Doit utiliser la suggestion @IMil
Matt Skeldon

1
le mettre dans la construction est une bonne idée IMil, cela a fonctionné pour moi .. j'ai essayé de le mettre sur un champ de classes statiques, mais (je pense) des champs de classes statiques initialisés lorsque vous les avez appelés pour la première fois, donc pas une solution sûre ..
Ibrahim Ozdemir

22

Cherchez-vous quelque chose comme ça:

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

Vous pouvez également le faire en vérifiant le nom du processus:

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

4
Fonctionne dans OnPaint, classes dérivées, constructeurs, etc. Meilleure solution encore.
Filip Kunc

14
IMHO, cela ressemble à une solution laide.
Camilo Martin

5
Attention possible fuite de mémoire ici. Le processus doit être éliminé.
nalply

7
Bien que je sois sûr que cela fonctionnera correctement dans la plupart des cas d'utilisation, cette solution présente un défaut principal: Visual Studio n'est (du moins en théorie) pas le seul hôte de conception. Par conséquent, cette solution ne fonctionnera que si votre concepteur est hébergé par une application appelée devenv.
stakx - ne contribue plus

2
Fonctionne sur VS2013, contrairement à la réponse actuellement acceptée.
Moby Disk

9

Component ... pour autant que je sache, n'a pas la propriété DesignMode. Cette propriété est fournie par Control. Mais le problème est que lorsque CustomControl se trouve dans un formulaire dans le concepteur, ce CustomControl s'exécute en mode d'exécution.

J'ai constaté que la propriété DesignMode ne fonctionne correctement que dans Form.


Merci pour le conseil! Je n'avais jamais réalisé cela auparavant, mais c'est parfaitement logique. L'utilisation de la méthode LicenseManager fournie par adrianbanks fonctionne parfaitement dans ces cas, où le contrôle est intégré dans un autre contrôle / formulaire. +1 pour chacun!
Josh Stribling

1
+1 Vous avez tout à fait raison, cela a également été mon expérience. Lorsque vous placez un contrôle utilisateur sur un formulaire, s'il existe des événements mouseenter ou charger, DesignMode apparaîtra toujours comme faux car vous n'êtes pas en mode de conception pour ce contrôle. D'après mon expérience, cela provoque le crash de Visual Studio.
Kyle B

8

Les contrôles (Forms, UserControls, etc.) héritent de Component classce qui a bool property DesignMode:

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

4
Ce qui n'est pas défini lorsque le constructeur s'exécute, c'est-à-dire le problème initial de l'OP. Le premier moment où vous pouvez l'utiliser est OnHandleCreated.
Ray le

8

IMPORTANT

Il y a une différence entre l'utilisation de Windows Forms ou de WPF !!

Ils ont des concepteurs différents et ont besoin de différents contrôles . De plus, c'est délicat lorsque vous mélangez des formulaires et des contrôles WPF. (par exemple, les contrôles WPF à l'intérieur d'une fenêtre Forms)

Si vous disposez uniquement de Windows Forms , utilisez ceci:

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

Si vous avez WPF uniquement , utilisez cette vérification:

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

Si vous avez une utilisation mixte de Forms et WPF, utilisez une vérification comme celle-ci:

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
}

Pour voir le mode actuel, vous pouvez afficher une MessageBox pour le débogage:

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

Remarque:

Vous devez ajouter les espaces de noms System.ComponentModel et System.Diagnostics .


Je pense que votre nom est trompeur. Lors de l'utilisation pour WinForms, le nom est 'isInWpfDesignerMode' et pour WPF, c'est 'isInFormsDesignerMode'
M Stoerzel

5

Vous devez utiliser la propriété Component.DesignMode. Autant que je sache, cela ne devrait pas être utilisé à partir d'un constructeur.


7
Cela ne fonctionne pas lorsque votre contrôle est à l'intérieur d'un autre contrôle ou formulaire en cours de conception.
Eric

1
En fait, cela fonctionne plutôt bien dans mes composants. J'ai toujours dû ajouter des if (!DesignMode)méthodes OnPaint pour m'assurer qu'il ne spammait pas le moment de la conception.
Bitterblue

4

Une autre méthode intéressante est décrite sur ce blog: http://www.undermyhat.org/blog/2009/07/in-depth-a-definitive-guide-to-net-user-controls-usage-mode-designmode-or -mode utilisateur/

Fondamentalement, il teste l'assembly en cours d'exécution référencé statiquement à partir de l'assembly d'entrée. Cela évite d'avoir à suivre les noms d'assemblages («devenv.exe», «monodevelop.exe» ..).

Cependant, cela ne fonctionne pas dans tous les autres scénarios, où l'assembly est chargé dynamiquement (VSTO en est un exemple).


Le lien est (effectivement) rompu. Il redirige maintenant vers le dernier article de blog (actuellement 2016-03) à la place.
Peter Mortensen

3

Avec la coopération du concepteur ... Il peut être utilisé dans les contrôles, les composants, dans tous les endroits

    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(les lignes doivent être supprimées. Cela me garantit seulement que cela fonctionne correctement.


3

Vous pouvez utiliser ceci

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

Cette réponse est pour WPF, la question concerne WinForms.
Rhys Jones

1

C'est la méthode que j'ai utilisée dans mon projet:

//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 !!!: Le code retourné booléen indique PAS en mode conception!


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

Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire sur la façon et / ou pourquoi il résout le problème améliorerait la valeur à long terme de la réponse.
Tiago Martins Peres 李大仁

0

La solution LicenseManager ne fonctionne pas dans OnPaint, cela non plus. J'ai eu recours à la même solution que @Jarek.

Voici la version en cache:

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

        return isDesignMode.Value;
    }

Sachez que cela échouera si vous utilisez un IDE tiers ou si Microsoft (ou votre utilisateur final) décide de changer le nom de l'exécutable VS en autre chose que «devenv». Le taux d'échec sera très faible, assurez-vous simplement de traiter toutes les erreurs qui pourraient survenir dans le code qui échoue à la suite de cela et tout ira bien.


0

Si vous souhaitez exécuter certaines lignes lorsqu'il est en cours d'exécution mais pas dans le concepteur Visual Studio, vous devez implémenter la propriété DesignMode comme suit:

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

0

Les minuteries activées par défaut peuvent provoquer des plantages lors de l'utilisation de contrôles personnalisés / utilisateur. Désactivez-les par défaut et activez-les uniquement après la vérification du mode de conception

   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;
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.