Виявлення режиму проектування від конструктора Control


99

Виходячи з цього запитання , чи можна виявити, чи знаходиться в режимі проектування чи часу виконання в конструкторі об'єкта?

Я розумію, що це може бути неможливим, і що мені доведеться змінити те, що я хочу, але наразі мене цікавить це конкретне питання.

Відповіді:


192

Ви можете використовувати перерахунок LicenceUsageMode у System.ComponentModelпросторі імен:

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

2
Елегантне рішення, воно працює краще, ніж функціонал C # ISite.DesignMode.
56ка

10
@Filip Kunc: якщо це не працює в OnPaint, ви можете перевірити цю умову в конструкторі та зберегти її в полі класу.
ІМіль

3
Це також не працює, коли перезапис WndProc в контролі користувача. Має використовувати пропозицію @IMil
Метт Скелдон

1
Поклавши його в конструкцію - це хороша ідея IMil, він працював на мене .. Я намагався поставити його на поле статичних класів, але (я думаю) поля статичних класів ініціалізуються, коли ви вперше викликали їх, тому не безпечне рішення ..
Ібрагім Оздемір

22

Шукаєте щось подібне:

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

Ви також можете це зробити, перевіривши ім'я процесу:

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

4
Працює в OnPaint, похідних класах, конструкторах тощо. Найкраще рішення досі.
Філіп Кунч

14
ІМХО, це виглядає як некрасиве рішення.
Каміло Мартін

5
Тут можливий витік пам'яті. Процес необхідно утилізувати.
nalply

7
Хоча я впевнений, що це спрацює добре у більшості випадків використання, це рішення має один головний недолік: Visual Studio є (принаймні теоретично) не єдиним господарем дизайнерів. Тому це рішення працюватиме лише в тому випадку, якщо ваш дизайнер розмістить програму під назвою devenv.
stakx - більше не вносять внесок

2
Працює над VS2013, на відміну від прийнятої відповіді.
Диск Moby

9

Компонент ... наскільки я знаю, не має властивості DesignMode. Цю властивість надає Контроль. Але проблема полягає в тому, що коли CustomControl розташований у формі у дизайнера, цей CustomControl працює в режимі виконання.

Я переконався, що властивість DesignMode працює правильно лише у формі.


Дякую за пораду! Я ніколи цього не усвідомлював, але це має ідеальний сенс. Використання методу LicenseManager, наданого adrianbanks, ідеально підходить у цих випадках, коли елемент управління вбудований в інший елемент управління / форму. +1 для кожного!
Джош Стриблінг

1
+1 Ви абсолютно праві, це був і мій досвід. Якщо ви розміщуєте елемент керування користувачем у формі, якщо є якісь миші, або події завантаження, DesignMode все одно з’явиться помилковим, оскільки ви не в дизайнерському режимі для цього керування. На мій досвід, це спричиняє крах візуальної студії.
Кайл Б

8

Органи управління (Форми, елементи управління UserControl і т.д.) успадкують Component classякий має bool property DesignModeтак:

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

4
Що не встановлено під час запуску конструктора, він також є початковою проблемою ОП. Перший момент, коли ви можете скористатися ним, - це в OnHandleCreated.
Рей

8

ВАЖЛИВО

Існує різниця у використанні Windows Forms або WPF !!

Вони мають різних дизайнерів і потребують різних перевірок . Крім того, складно, коли ви змішуєте елементи Forms та WPF. (наприклад, елементи керування WPF всередині вікна Форми)

Якщо у вас є лише Windows Forms , використовуйте це:

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

Якщо у вас є лише WPF , використовуйте цю перевірку:

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

Якщо у вас змішане використання Forms та WPF, використовуйте такий чек:

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
}

Щоб побачити поточний режим, ви можете показати MessageBox для налагодження:

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

Зауваження:

Вам потрібно додати простори імен System.ComponentModel та System.Diagnostics .


Я думаю, що ваше називання вводить в оману. При використанні для WinForms назва називається "isInWpfDesignerMode", а для WPF - це "isInFormsDesignerMode"
M Stoerzel

5

Ви повинні використовувати властивість Component.DesignMode. Наскільки мені відомо, це не повинно використовуватися конструктором.


7
Це не працює, якщо ваш контроль знаходиться в іншому контролі або формі, що розробляється.
Ерік

1
Насправді це дуже добре працює в моїх компонентах. Мені завжди доводилося додавати if (!DesignMode)методи OnPaint, щоб переконатися, що він не спамує час розробки.
Bitterblue

4

Ще один цікавий метод описаний у цьому блозі: http://www.undermyhat.org/blog/2009/07/in-depth-a-definitive-guide-to-net-user-controls-usage-mode-designmode-or -використання /

В основному, він перевіряє, чи виконується збірка статично посилається на вхідну збірку. Він обходить необхідність відстежувати назви збірок ('devenv.exe', 'monodevelop.exe' ..).

Однак це не працює у всіх інших сценаріях, де збірка динамічно завантажується (VSTO є одним із прикладів).


Посилання (ефективно) порушено. Тепер він переспрямовує на останню публікацію блогу (на даний час 2016-03).
Пітер Мортенсен

3

За співпраці дизайнера ... Його можна використовувати в управліннях, компонентах, у будь-яких місцях

    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(лінії слід видалити. Це лише переконує, що вона працює правильно.



1

Це метод, який я використовував у своєму проекті:

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

Увага !!!: Код, повернутий bool, вказує НЕ в режимі проектування!


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

Хоча цей код може відповісти на питання, надаючи додатковий контекст щодо того, як та / або чому він вирішує проблему, покращить довгострокове значення відповіді.
Tiago Martins Peres 李大仁

0

Рішення LicenseManager не працює всередині OnPaint, а також не це. DesignMode. Я вдався до того ж рішення, що і @Jarek.

Ось кешована версія:

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

        return isDesignMode.Value;
    }

Будьте в курсі, що це не вдасться, якщо ви використовуєте будь-який сторонній IDE або якщо Microsoft (або ваш кінцевий користувач) вирішили змінити ім'я виконуваного файлу VS на щось інше, ніж "devenv". Коефіцієнт відмов буде дуже низьким, просто переконайтеся, що ви вирішите будь-які виникаючі помилки, які можуть виникнути в коді, який виходить з ладу в результаті цього, і ви будете добре.


0

Якщо ви хочете запустити деякі рядки, коли він запущений, але не в дизайнері Visual Studio, слід реалізувати властивість DesignMode наступним чином:

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

Тимери, увімкнені за замовчуванням, можуть спричинити збій при використанні користувальницьких / користувальницьких елементів керування. Вимкніть їх за замовчуванням і ввімкніть лише після перевірки режиму проектування

   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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.