Кто-нибудь нашел полезное решение проблемы DesignMode при разработке элементов управления?
Проблема в том, что при вложении элементов управления режим DesignMode работает только для первого уровня. DesignMode второго и более низких уровней всегда будет возвращать FALSE.
Стандартный взлом заключался в том, чтобы посмотреть на имя запущенного процесса, и если это "DevEnv.EXE", то это должна быть студия, поэтому DesignMode действительно ИСТИНА.
Проблема, связанная с поиском ProcessName, работает через реестр и другие странные части, в результате чего пользователь может не иметь необходимых прав для просмотра имени процесса. Вдобавок этот странный маршрут очень медленный. Таким образом, нам пришлось накапливать дополнительные хаки для использования синглтона, и если при запросе имени процесса возникает ошибка, предположим, что DesignMode имеет значение FALSE.
Хороший чистый способ определить DesignMode в порядке. На самом деле было бы даже лучше заставить Microsoft исправить это внутри фреймворка!
Сообщение в с описанием возможных решений проблемы . Max Galkin 22.05.2009
+1 за то, чтобы заставить Microsoft исправить это внутренне во фреймворке, было бы даже лучше - десять минут чьего-то времени сэкономили бы десятки тысяч человек по часам. Если есть одна программа, которая полагается на ошибку, и 100000, которым она причиняет неудобства, не имеет смысла сохранять ошибку, чтобы избежать неудобств для одной программы! BlueRaja - Danny Pflughoeft 22.04.2010
Привет, это было опубликовано в 2008 году. Теперь это исправлено? Jake 04.12.2012
В VS 2012 это осталось прежним. Boogier 05.02.2014
Обратите внимание, что при использовании специального конструктора для UserControl (например, я тестировал с классом, производным от ControlDesigner), тогда вызов EnableDesignMode (subControl), похоже, заставляет свойство DesignMode субэлемента управления работать. Однако это не эффективное решение проблемы, поскольку мы не всегда создаем контейнер, в котором находится наш элемент управления. Protongun 22.08.2014
Чтобы попытаться понять три предложенных решения, я создал небольшое тестовое решение - с тремя проектами:
TestApp (приложение winforms),
Подконтроль (dll)
SubSubControl (dll)
Затем я встроил SubSubControl в SubControl, а затем по одному в TestApp.Form.
На этом скриншоте показан результат при запуске.
На этом снимке экрана показан результат с формой, открытой в Visual Studio:
Заключение: казалось бы, что без отражения единственный надежный внутри конструктор - это LicenseUsage, и единственный надежный вне конструктор IsDesignedHosted (см. BlueRaja ниже)
PS: См. Комментарий ToolmakerSteve ниже (который я не тестировал): "Обратите внимание, что ответ IsDesignerHosted был обновлен и теперь включает LicenseUsage ..., так что теперь тест может быть просто if (IsDesignerHosted). Альтернативный подход - проверить LicenseManager в конструкторе и кэшировать результат. "
Ответ 2 · рейтинг 33 · BlueRaja - Danny Pflughoeft
С этой страницы:
([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; Я сомневаюсь, что он куда-то пойдет, но все равно проголосуйте за него, так как это, очевидно, ошибка (неважно, "по замыслу").
Ответ 3 · рейтинг 29 · hopla
Почему бы вам не проверить LicenseManager.UsageMode. Это свойство может иметь значения LicenseUsageMode.Runtime или LicenseUsageMode.Designtime.
Если вы хотите, чтобы код запускался только во время выполнения, используйте следующий код:
if (LicenseManager.UsageMode == LicenseUsageMode.Runtime)
{
bla bla bla...
}
Ответ 4 · рейтинг 7 · husayt
Это метод, который я использую внутри форм:
/// <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 не сработает.
Ответ 5 · рейтинг 5 · Jonathan
Я использую метод 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
Ответ 6 · рейтинг 3 · Boris B.
Поскольку ни один из методов не является надежным (DesignMode, LicenseManager) или эффективным (процесс, рекурсивные проверки), я использую public static bool Runtime { get; private set } на уровне программы и явно устанавливаю его внутри метода Main ().
Ответ 7 · рейтинг 3 · juFo
Мы успешно используем этот код:
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";
}
}
Ответ 8 · рейтинг 3 · user2785562
Мое предложение - оптимизация ответа @ 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;
}
}
}
Ответ 9 · рейтинг 2 · Will Dean
Меня это никогда не ловило, но не могли бы вы просто пройти обратно по родительской цепочке от элемента управления, чтобы увидеть, установлен ли DesignMode где-нибудь над вами?
Ответ 10 · рейтинг 1 · Craig
DesignMode - это частная собственность (насколько я могу судить). Ответ состоит в том, чтобы предоставить общедоступное свойство, которое предоставляет свойство DesignMode. Затем вы можете каскадировать резервную копию цепочки пользовательских элементов управления, пока не столкнетесь с непользовательским элементом управления или элементом управления, находящимся в режиме разработки. Что-то вроде этого....
public bool RealDesignMode()
{
if (Parent is MyBaseUserControl)
{
return (DesignMode ? true : (MyBaseUserControl) Parent.RealDesignMode;
}
return DesignMode;
}
Где все ваши UserControls наследуются от MyBaseUserControl. В качестве альтернативы вы можете реализовать интерфейс, который предоставляет "RealDeisgnMode".
Обратите внимание, что этот код не является живым кодом, он просто отключен от манжеты. :)
Ответ 11 · рейтинг 1 · Will Dean
Я не понимал, что вы не можете вызвать Parent.DesignMode (и я тоже кое-что узнал о 'protected' в C # ...)
Вот отражающая версия: (я подозреваю, что создание статического поля designModeProperty может дать преимущество в производительности)
Недавно мне пришлось бороться с этой проблемой в 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;
}