Кто-нибудь нашел полезное решение проблемы DesignMode при разработке элементов управления?
Проблема в том, что при вложении элементов управления режим DesignMode работает только для первого уровня. DesignMode второго и более низких уровней всегда будет возвращать FALSE.
Стандартный взлом заключался в том, чтобы посмотреть на имя запущенного процесса, и если это «DevEnv.EXE», то это должна быть студия, поэтому DesignMode действительно ИСТИНА.
Проблема, связанная с поиском ProcessName, проходит через реестр и другие странные части с конечным результатом, что у пользователя может не быть необходимых прав для просмотра имени процесса. Вдобавок этот странный маршрут очень медленный. Таким образом, нам пришлось нагромождать дополнительные хаки для использования синглтона, и если при запросе имени процесса возникает ошибка, предположим, что DesignMode имеет значение FALSE.
Хороший чистый способ определить DesignMode в порядке. На самом деле было бы даже лучше заставить Microsoft исправить это внутри фреймворка!
источник
Ответы:
Возвращаясь к этому вопросу, я обнаружил 5 различных способов сделать это, а именно:
System.ComponentModel.DesignMode property System.ComponentModel.LicenseManager.UsageMode property private string ServiceString() { if (GetService(typeof(System.ComponentModel.Design.IDesignerHost)) != null) return "Present"; else return "Not present"; } public bool IsDesignerHosted { get { Control ctrl = this; while(ctrl != null) { if((ctrl.Site != null) && ctrl.Site.DesignMode) return true; ctrl = ctrl.Parent; } return false; } } public static bool IsInDesignMode() { return System.Reflection.Assembly.GetExecutingAssembly() .Location.Contains("VisualStudio")) }
Чтобы попытаться понять три предложенных решения, я создал небольшое тестовое решение - с тремя проектами:
Затем я встроил SubSubControl в SubSubControl, а затем по одному в TestApp.Form.
На этом скриншоте показан результат при запуске.
На этом снимке экрана показан результат с формой, открытой в Visual Studio:
Заключение: может показаться, что без отражения единственный надежный внутри конструктора - это LicenseUsage, а единственный надежный вне конструктора - IsDesignedHosted (от BlueRaja ниже)
PS: См. Комментарий ToolmakerSteve ниже (который я не тестировал): «Обратите внимание, что ответ IsDesignerHosted был обновлен, чтобы включить LicenseUsage ..., поэтому теперь тест может быть просто if (IsDesignerHosted). Альтернативный подход - проверить LicenseManager в конструкторе и кешировать результат . "
источник
if(LicenseUseage == LicenseUsageMode.Designtime || IsDesignerHosted)
был бы 100% правильный подход?LicenseUsage...
, поэтому теперь тест можно простоif (IsDesignerHosted)
. Альтернативный подход - протестировать LicenseManager в конструкторе и кэшировать результат .С этой страницы :
( [Edit 2013] Отредактировано для работы в конструкторах с использованием метода, предоставленного @hopla)
/// <summary> /// The DesignMode property does not correctly tell you if /// you are in design mode. IsDesignerHosted is a corrected /// version of that property. /// (see https://connect.microsoft.com/VisualStudio/feedback/details/553305 /// and http://stackoverflow.com/a/2693338/238419 ) /// </summary> public bool IsDesignerHosted { get { if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) return true; Control ctrl = this; while (ctrl != null) { if ((ctrl.Site != null) && ctrl.Site.DesignMode) return true; ctrl = ctrl.Parent; } return false; } }
Я отправил отчет об ошибке в Microsoft; Я сомневаюсь, что он куда-то пойдет, но все равно проголосуйте за него, так как это, очевидно, ошибка (независимо от того, является ли она «задуманной» ).
источник
Почему бы вам не проверить LicenseManager.UsageMode. Это свойство может иметь значения LicenseUsageMode.Runtime или LicenseUsageMode.Designtime.
Если вы хотите, чтобы код запускался только во время выполнения, используйте следующий код:
if (LicenseManager.UsageMode == LicenseUsageMode.Runtime) { bla bla bla... }
источник
Это метод, который я использую внутри форм:
/// <summary> /// Gets a value indicating whether this instance is in design mode. /// </summary> /// <value> /// <c>true</c> if this instance is in design mode; otherwise, <c>false</c>. /// </value> protected bool IsDesignMode { get { return DesignMode || LicenseManager.UsageMode == LicenseUsageMode.Designtime; } }
Таким образом, результат будет правильным, даже если одно из свойств DesignMode или LicenseManager не сработает.
источник
Я использую метод LicenseManager, но кэширую значение из конструктора для использования в течение всего жизненного цикла экземпляра.
public MyUserControl() { InitializeComponent(); m_IsInDesignMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime); } private bool m_IsInDesignMode = true; public bool IsInDesignMode { get { return m_IsInDesignMode; } }
Версия VB:
Sub New() InitializeComponent() m_IsInDesignMode = (LicenseManager.UsageMode = LicenseUsageMode.Designtime) End Sub Private ReadOnly m_IsInDesignMode As Boolean = True Public ReadOnly Property IsInDesignMode As Boolean Get Return m_IsInDesignMode End Get End Property
источник
Мы успешно используем этот код:
public static bool IsRealDesignerMode(this Control c) { if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime) return true; else { Control ctrl = c; while (ctrl != null) { if (ctrl.Site != null && ctrl.Site.DesignMode) return true; ctrl = ctrl.Parent; } return System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv"; } }
источник
Мое предложение является оптимизацией @ blueraja-Danny-pflughoeft ответа . Это решение вычисляет результат не каждый раз, а только в первый раз (объект не может изменить UsageMode с дизайна на время выполнения)
private bool? m_IsDesignerHosted = null; //contains information about design mode state /// <summary> /// The DesignMode property does not correctly tell you if /// you are in design mode. IsDesignerHosted is a corrected /// version of that property. /// (see https://connect.microsoft.com/VisualStudio/feedback/details/553305 /// and https://stackoverflow.com/a/2693338/238419 ) /// </summary> [Browsable(false)] public bool IsDesignerHosted { get { if (m_IsDesignerHosted.HasValue) return m_IsDesignerHosted.Value; else { if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) { m_IsDesignerHosted = true; return true; } Control ctrl = this; while (ctrl != null) { if ((ctrl.Site != null) && ctrl.Site.DesignMode) { m_IsDesignerHosted = true; return true; } ctrl = ctrl.Parent; } m_IsDesignerHosted = false; return false; } } }
источник
Меня это никогда не ловило, но не могли бы вы просто пройти обратно по родительской цепочке от элемента управления, чтобы увидеть, установлен ли DesignMode где-нибудь над вами?
источник
Поскольку ни один из методов не является надежным (DesignMode, LicenseManager) или эффективным (процесс, рекурсивные проверки), я использую
public static bool Runtime { get; private set }
на уровне программы и явно устанавливаю его внутри метода Main ().источник
DesignMode - частная собственность (насколько я могу судить). Ответ - предоставить общедоступное свойство, которое предоставляет свойство DesignMode. Затем вы можете выполнить каскадное резервное копирование цепочки пользовательских элементов управления до тех пор, пока не столкнетесь с непользовательским элементом управления или элементом управления, находящимся в режиме разработки. Что-то вроде этого....
public bool RealDesignMode() { if (Parent is MyBaseUserControl) { return (DesignMode ? true : (MyBaseUserControl) Parent.RealDesignMode; } return DesignMode; }
Где все ваши UserControl наследуются от MyBaseUserControl. В качестве альтернативы вы можете реализовать интерфейс, который предоставляет «RealDeisgnMode».
Обратите внимание, что этот код не является живым кодом, он просто отключен. :)
источник
Я не понимал, что вы не можете вызвать Parent.DesignMode (и я тоже кое-что узнал о 'protected' в C # ...)
Вот отражающая версия: (Я подозреваю, что создание статического поля designModeProperty может дать преимущество в производительности)
static bool IsDesignMode(Control control) { PropertyInfo designModeProperty = typeof(Component). GetProperty("DesignMode", BindingFlags.Instance | BindingFlags.NonPublic); while (designModeProperty != null && control != null) { if((bool)designModeProperty.GetValue(control, null)) { return true; } control = control.Parent; } return false; }
источник
Недавно мне пришлось бороться с этой проблемой в Visual Studio 2017 при использовании вложенных UserControls. Я комбинирую несколько подходов, упомянутых выше и в других местах, а затем настраивал код, пока не получил достойный метод расширения, который пока работает приемлемо. Он выполняет последовательность проверок, сохраняя результат в статических логических переменных, поэтому каждая проверка выполняется не более одного раза во время выполнения. Процесс может быть излишним, но он мешает запуску кода в студии. Надеюсь, это кому-то поможет.
public static class DesignTimeHelper { private static bool? _isAssemblyVisualStudio; private static bool? _isLicenseDesignTime; private static bool? _isProcessDevEnv; private static bool? _mIsDesignerHosted; /// <summary> /// Property <see cref="Form.DesignMode"/> does not correctly report if a nested <see cref="UserControl"/> /// is in design mode. InDesignMode is a corrected that property which . /// (see https://connect.microsoft.com/VisualStudio/feedback/details/553305 /// and https://stackoverflow.com/a/2693338/238419 ) /// </summary> public static bool InDesignMode( this Control userControl, string source = null) => IsLicenseDesignTime || IsProcessDevEnv || IsExecutingAssemblyVisualStudio || IsDesignerHosted(userControl); private static bool IsExecutingAssemblyVisualStudio => _isAssemblyVisualStudio ?? (_isAssemblyVisualStudio = Assembly .GetExecutingAssembly() .Location.Contains(value: "VisualStudio")) .Value; private static bool IsLicenseDesignTime => _isLicenseDesignTime ?? (_isLicenseDesignTime = LicenseManager.UsageMode == LicenseUsageMode.Designtime) .Value; private static bool IsDesignerHosted( Control control) { if (_mIsDesignerHosted.HasValue) return _mIsDesignerHosted.Value; while (control != null) { if (control.Site?.DesignMode == true) { _mIsDesignerHosted = true; return true; } control = control.Parent; } _mIsDesignerHosted = false; return false; } private static bool IsProcessDevEnv => _isProcessDevEnv ?? (_isProcessDevEnv = Process.GetCurrentProcess() .ProcessName == "devenv") .Value; }
источник