Как узнать, выполняется ли код .NET дизайнером Visual Studio

Когда я открываю форму Windows Forms в конструкторе Visual Studio, в моем коде появляются ошибки. Я хотел бы выполнить ветвление в своем коде и выполнить другую инициализацию, если форма открывается дизайнером, а не если она запускается по-настоящему.

Как я могу определить во время выполнения, выполняется ли код как часть конструктора, открывающего форму?


person Zvi    schedule 16.09.2008    source источник


Ответы (21)


Чтобы узнать, находитесь ли вы в «режиме дизайна»:

  • Компоненты Windows Forms (и элементы управления) имеют режим дизайна собственность.
  • Элементы управления Windows Presentation Foundation должны использовать прикрепленный IsInDesignMode имущество.
person Roger Lipscombe    schedule 16.09.2008
comment
DesignMode не на 100% надежен. - person dwidel; 05.01.2011
comment
... см. ответ JohnV для обсуждения (и решений) проблем DesignMode. - person Roger Lipscombe; 06.01.2011
comment
См. Ответ NET3 для рабочего решения. Никакого неуважения к Джону В. - person JMD; 08.10.2014

Свойство Control.DesignMode, вероятно, то, что вы ищете. Он сообщает вам, открыт ли родительский элемент управления в конструкторе.

В большинстве случаев он работает отлично, но есть случаи, когда он работает не так, как ожидалось. Во-первых, это не работает в конструкторе элементов управления. Во-вторых, DesignMode является ложным для «внучатых» элементов управления. Например, DesignMode для элементов управления, размещенных в UserControl, вернет false, если UserControl размещен в родительском элементе.

Есть довольно простой обходной путь. Это выглядит примерно так:

public bool HostedDesignMode
{
  get 
  {
     Control parent = Parent;
     while (parent!=null)
     {
        if(parent.DesignMode) return true;
        parent = parent.Parent;
     }
     return DesignMode;
  }
}

Я не тестировал этот код, но он должен работать.

person JohnV    schedule 16.09.2008
comment
это не работает DesignMode защищен. Но проблема, о которой вы говорите, - это именно то, что я получаю. Но я также получаю это, если помещаю код в OnLoad () вместо .cor () - person particle; 20.04.2010

Самый надежный подход:

public bool isInDesignMode
{
    get
    {
        System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
        bool res = process.ProcessName == "devenv";
        process.Dispose();
        return res;
    }
}
person GWLlosa    schedule 09.12.2008
comment
Это также можно использовать для определения того, работаете ли вы в отладчике IDE, если вы используете в качестве критерия process.ProcessName.Contains (vshost). - person zmilojko; 07.09.2012
comment
Поправка для VS2013: поскольку редактор XAML, наконец, получил свой собственный процесс, вам необходимо проверить наличие XDesProc - person Seven; 13.05.2015
comment
Хотя это вполне разумное решение и, вероятно, очень надежное, в этом ответе есть что-то, что заставляет меня дрожать по спине. - person Neil; 01.10.2015
comment
... если только имя процесса вашего собственного приложения не называется devenv (и я предполагаю, что могут применяться и другие исключения). Я бы не назвал самым надежным подход тот, в котором есть явный недостаток. Да, пользователь может изменить имя файла на devenv.exe, и ваше приложение внезапно перестанет работать должным образом. - person Spook; 07.02.2020

Самый надежный способ сделать это - игнорировать свойство DesignMode и использовать собственный флаг, который устанавливается при запуске приложения.

Класс:

public static class Foo
{
    public static bool IsApplicationRunning { get; set; }
}

Program.cs:

[STAThread]
static void Main()
{
     Foo.IsApplicationRunning = true;
     // ... code goes here ...
}

Тогда просто проверьте флаг там, где он вам нужен.

if(Foo.IsApplicationRunning)
{
    // Do runtime stuff
}
else
{
    // Do design time stuff
}
person Marty    schedule 18.10.2011
comment
Я потратил много времени на пробу различных решений, но в конце концов мне пришла в голову идея просто установить флаг. Это единственный способ, который работает на 100%. - person dwidel; 31.12.2011
comment
Однако это не работает для библиотек кода, и тогда это должно быть включено в вызов всех методов, которые в этом нуждаются. - person Johny Skovdal; 27.09.2012
comment
Используйте глобальную переменную и установите ее один раз. - person dwidel; 06.11.2012
comment
Я действительно не вижу в этом смысла. Если я чего-то не упускаю, он не отвечает на вопрос, как определить, работает ли он в отладчике - он требует, чтобы вы вручную установили флаг, чтобы указать это. - person WiredEarp; 18.01.2017

У меня была такая же проблема в Visual Studio Express 2013. Я пробовал многие из предложенных здесь решений, но то, что сработало для меня, было ответом на другая ветка, которую я повторю здесь, если ссылка когда-нибудь сломается:

protected static bool IsInDesigner
{
    get { return (Assembly.GetEntryAssembly() == null); }
}
person GeeC    schedule 10.02.2015

Подход devenv перестал работать в VS2012, поскольку у дизайнера теперь есть собственный процесс. Вот решение, которое я сейчас использую (часть devenv оставлена ​​в наследство, но без VS2010 я не могу это проверить).

private static readonly string[] _designerProcessNames = new[] { "xdesproc", "devenv" };

private static bool? _runningFromVisualStudioDesigner = null;
public static bool RunningFromVisualStudioDesigner
{
  get
  {
    if (!_runningFromVisualStudioDesigner.HasValue)
    {
      using (System.Diagnostics.Process currentProcess = System.Diagnostics.Process.GetCurrentProcess())
      {
        _runningFromVisualStudioDesigner = _designerProcessNames.Contains(currentProcess.ProcessName.ToLower().Trim());
      }
    }

    return _runningFromVisualStudioDesigner.Value;
  }
}
person Johny Skovdal    schedule 27.09.2012
comment
Как ты это узнал? - person Sebastian; 24.11.2013
comment
Слишком давно я не могу вспомнить, что боюсь. Думаю, я только что заметил странные процессы в диспетчере задач и просмотрел их, но я не могу сказать наверняка. - person Johny Skovdal; 24.11.2013
comment
Поскольку я действительно благодарен за это замечание, мне уже было интересно, почему некоторые из моих компонентов вызывают сбои в новой Visual Studio, к сожалению, неперехваченные исключения могут вызвать сбой всей Visual Studio (т.е. ошибку в неуправляемом методе Dispose) - person Sebastian; 24.11.2013
comment
Рад, что ты нашел это полезным. :) Извините, я не могу больше помочь в том, как я обнаружил ошибку. - person Johny Skovdal; 24.11.2013

Это хакерский, но если вы используете VB.NET и когда вы re, запущенный из Visual Studio My.Application.Deployment.CurrentDeployment, будет иметь значение Nothing, потому что вы еще не развернули его. Я не уверен, как проверить эквивалентное значение в C #.

person Joel Coehoorn    schedule 16.09.2008

using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess())
{
    bool inDesigner = process.ProcessName.ToLower().Trim() == "devenv";
    return inDesigner;
}

Я попробовал приведенный выше код (добавил оператор using), и в некоторых случаях у меня не получалось. Тестирование в конструкторе пользовательского элемента управления размещается непосредственно в форме с загрузкой дизайнера при запуске. Но работал бы в других местах.

Что сработало для меня во всех местах:

private bool isDesignMode()
{
    bool bProcCheck = false;
    using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess())
    {
        bProcCheck = process.ProcessName.ToLower().Trim() == "devenv";
    }

    bool bModeCheck = (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime);

    return bProcCheck || DesignMode || bModeCheck;
}

Может быть, это немного переборщило, но это работает, так что для меня этого достаточно.

Успех в приведенном выше примере - это bModeCheck, поэтому, вероятно, DesignMode лишний.

person Martin    schedule 15.12.2012
comment
Я считаю, что это лучшее решение, так как оно охватывает все ситуации. У меня отлично сработало. - person Amito; 08.04.2013

Вы проверяете свойство DesignMode своего элемента управления:

if (!DesignMode)
{
//Do production runtime stuff
}

Обратите внимание, что это не будет работать в вашем конструкторе, потому что компоненты еще не инициализированы.

person Ryan Steckler    schedule 16.09.2008

При запуске проекта к его имени добавляется ".vshost".

Итак, я использую это:

    public bool IsInDesignMode
    {
        get
        {
            Process p = Process.GetCurrentProcess();
            bool result = false;

            if (p.ProcessName.ToLower().Trim().IndexOf("vshost") != -1)
                result = true;
            p.Dispose();

            return result;
        }
    }

Меня устраивает.

person Andy    schedule 24.06.2012
comment
Это позволяет узнать, запускается ли программа из VS, а не вызываются ли методы из дизайнера VS, чего и пытается добиться Zvi. - person Johny Skovdal; 27.09.2012

Я не уверен, что работа в режиме отладки считается реальной, но простой способ - включить в код выражение if, которое проверяет наличие System.Diagnostics.Debugger.IsAttached.

person Adrian Anttila    schedule 16.09.2008

Если вы создали свойство, которое вам вообще не нужно во время разработки, вы можете использовать атрибут DesignerSerializationVisibility и установить для него значение Hidden. Например:

protected virtual DataGridView GetGrid()
{
    throw new NotImplementedException("frmBase.GetGrid()");
}

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int ColumnCount { get { return GetGrid().Columns.Count; } set { /*Some code*/ } }

Это предотвращало сбой моей Visual Studio каждый раз, когда я вносил изменения в форму с помощью NotImplementedException() и пытался сохранить. Вместо этого Visual Studio знает, что я не хочу сериализовать это свойство, поэтому может его пропустить. Он отображает только какую-то странную строку в поле свойств формы, но ее можно безопасно игнорировать.

Обратите внимание, что это изменение не вступит в силу до тех пор, пока вы не выполните повторную сборку.

person Bolek    schedule 13.07.2012

Мы используем следующий код в UserControls, и он выполняет свою работу. Использование только DesignMode не будет работать в вашем приложении, которое использует ваши пользовательские элементы управления, как указано другими участниками.

    public bool IsDesignerHosted
    {
        get { return IsControlDesignerHosted(this); }
    }

    public bool IsControlDesignerHosted(System.Windows.Forms.Control ctrl)
    {
        if (ctrl != null)
        {
            if (ctrl.Site != null)
            {
                if (ctrl.Site.DesignMode == true)
                    return true;
                else
                {
                    if (IsControlDesignerHosted(ctrl.Parent))
                        return true;
                    else
                        return false;
                }
            }
            else
            {
                if (IsControlDesignerHosted(ctrl.Parent))
                    return true;
                else
                    return false;
            }
        }
        else
            return false;
    }

В основном приведенная выше логика сводится к следующему:

    public bool IsControlDesignerHosted(System.Windows.Forms.Control ctrl)
    {
        if (ctrl == null) return false;
        if (ctrl.Site != null && ctrl.Site.DesignMode) return true;
        return IsControlDesignerHosted(ctrl.Parent);
    }
person Community    schedule 09.12.2008

Если вы находитесь в форме или элементе управления, вы можете использовать свойство DesignMode:

if (DesignMode)
{
        DesignMode Only stuff
}
person Akselsson    schedule 16.09.2008
comment
Кажется, это не работает в элементах управления - всегда возвращает false :( - person Danny Tuppeny; 16.07.2011

Я обнаружил, что свойство DesignMode содержит ошибки, по крайней мере, в предыдущих версиях Visual Studio. Следовательно, я сделал свой собственный, используя следующую логику:

Process.GetCurrentProcess().ProcessName.ToLower().Trim() == "devenv";

Я знаю, что это вроде взлома, но он работает хорошо.

person Eyvind    schedule 09.12.2008
comment
Это не сработает, если дизайнер размещен не в Visual Studio, а где-то еще. Например, дизайнер веб-страниц также используется в SharePoint Designer и Expression Web. Дизайнер рабочего процесса можно разместить где угодно. - person John Saunders; 16.07.2009
comment
Process.GetCurrentProcess (). ProcessName.ToLower (). Trim () == devenv; вызывает утечку памяти. Вы должны избавиться от объекта процесса. - person Matthew; 17.12.2009
comment
Это единственная причина МАССОВОЙ утечки памяти в моем приложении. - person xster; 04.04.2010
comment
Это КЛЮЧ! Эта строка действительно вызывает массовую утечку памяти. Используйте утилизацию! - person xster; 04.04.2010
comment
Чтобы прояснить для всех, ваш код должен выглядеть примерно так: System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess(); bool inDesigner = process.ProcessName.ToLower().Trim() == "devenv"; process.Dispose(); if (isDesigner) ... - person Amit Bens; 07.04.2011
comment
@xster не забудьте утилизировать - using (var p = Process.GetCurrentProcess()) { ... } - person Keith; 20.04.2012
comment
Из любопытства, почему по умолчанию не производится сборка мусора? - person Uri; 02.12.2013

Чтобы решить эту проблему, вы также можете ввести код, как показано ниже:

private bool IsUnderDevelopment
{
    get
    {
        System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
        if (process.ProcessName.EndsWith(".vshost")) return true;
        else return false;
    }

}
person Ali Reza Kalantar    schedule 05.03.2013
comment
который проверяет, запущен ли он в отладчике, но мы говорим о VS Designer - person Sebastian; 30.11.2013

Вот еще один:

        //Caters only to thing done while only in design mode
        if (App.Current.MainWindow == null){ // in design mode  }

        //Avoids design mode problems
        if (App.Current.MainWindow != null) { //applicaiton is running }
person JWP    schedule 13.03.2015

После тестирования большинства ответов здесь, к сожалению, у меня ничего не сработало (VS2015). Поэтому я добавил небольшой поворот к ответу JohnV, который не сработал из коробки, поскольку DesignMode является защищенным свойством. в классе Control.

Сначала я сделал метод расширения, который возвращает значение свойства DesignMode через Reflection:

public static Boolean GetDesignMode(this Control control)
{
    BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static;
    PropertyInfo prop = control.GetType().GetProperty("DesignMode", bindFlags);
    return (Boolean)prop.GetValue(control, null);
}

а затем я сделал такую ​​функцию, как JohnV:

public bool HostedDesignMode
{
    get
    {
        Control parent = Parent;
        while (parent != null)
        {
            if (parent.GetDesignMode()) return true;
            parent = parent.Parent;
        }
        return DesignMode;
    }
}

Это единственный метод, который сработал для меня, избегая всего беспорядка ProcessName, и, хотя отражение не следует использовать легкомысленно, в данном случае все изменилось! ;)

РЕДАКТИРОВАТЬ:

Вы также можете сделать вторую функцию методом расширения следующим образом:

public static Boolean IsInDesignMode(this Control control)
{
    Control parent = control.Parent;
    while (parent != null)
    {
        if (parent.GetDesignMode())
        {
            return true;
        }
        parent = parent.Parent;
    }
    return control.GetDesignMode();
}
person Gpower2    schedule 16.03.2016
comment
Насколько медленно вызывается эта функция во время выполнения? - person rolls; 28.07.2017

Вот гибкий способ, который можно адаптировать к тому, откуда вы компилируете, а также независимо от того, в каком режиме вы находитесь.

string testString1 = "\\bin\\";
//string testString = "\\bin\\Debug\\";
//string testString = "\\bin\\Release\\";

if (AppDomain.CurrentDomain.BaseDirectory.Contains(testString))
{
    //Your code here
}
person Gary    schedule 12.05.2015
comment
Это не кажется надежным? Что, если пользователь сменит каталог, из которого он бежит? - person Petr; 12.05.2015

person    schedule
comment
+1. В качестве альтернативы LicenseUsageMode.Runtime для всего, что должно выполняться только во время выполнения. - person JMD; 08.10.2014
comment
+1 Это доставило мне удовольствие. Использовал режим DesignMode, который, как оказалось, совершенно ненадежен. Переключил все использования на эту альтернативу UsageMode. - person Tomás; 07.05.2015
comment
Решение LicenseManager помогло мне подавить код, который выполняется во время загрузки модуля .cctor и вызывал плохое поведение в конструкторе WPF. - person Aaron Hudon; 08.10.2015
comment
Этот сработал у меня, свойство .DesignMode у меня не сработало. - person Patrick from NDepend team; 11.01.2016
comment
В Visual Studio 2017 это работает в конструкторе элемента управления, но не в обработчике событий загрузки элемента управления; там он всегда установлен на время выполнения ‹sigh› Конечно, нетрудно обойтись (просто установите переменную-член в конструкторе), но просто ... странно. - person Jimmy; 14.02.2019
comment
К сожалению, не работает для миграции Dotnet Core EF. - person cdonner; 24.03.2021

person    schedule
comment
Он говорит, что он недоступен, потому что он защищен - person Scott Whitlock; 22.02.2013