DesignMode с вложенными элементами управления
Кто-нибудь нашел полезное решение проблемы DesignMode при разработке элементов управления?
Проблема в том, что если вы вставляете элементы управления, то DesignMode работает только для первого уровня. Второй и нижний уровни DesignMode всегда будут возвращать FALSE.
Стандартным взломом было посмотреть имя запущенного процесса, и если это "DevEnv.EXE", тогда он должен быть студией, поэтому DesignMode действительно TRUE.
Проблема с поиском ProcessName пробивается через реестр и другие странные части, в результате чего пользователь может не иметь необходимых прав на просмотр имени процесса. Кроме того, этот странный маршрут очень медленный. Таким образом, нам пришлось собрать дополнительные хаки для использования синглета, и если при запросе имени процесса возникает ошибка, предположим, что DesignMode FALSE.
Хороший чистый способ определения DesignMode в порядке. Повсеместно заставить Microsoft исправить ее внутри рамки будет еще лучше!
Ответы
Ответ 1
Повторяя этот вопрос, я теперь "открыл" 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"))
}
Чтобы попытаться найти три предложенных решения, я создал небольшое тестовое решение - с тремя проектами:
- TestApp (приложение winforms),
- SubControl (dll)
- SubSubControl (dll)
Затем я включил SubSubControl в SubControl, затем один из каждого в TestApp.Form.
Этот снимок экрана показывает результат при запуске.
![Screenshot of running]()
Этот снимок экрана показывает результат с открытой формой в Visual Studio:
![Screenshot of not running]()
Заключение: Казалось бы, что без отражения единственная, которая надежна внутри конструктора, является LicenseUsage, и единственной надежной вне конструктора является IsDesignedHosted (by BlueRaja ниже)
PS: см. комментарий ToolmakerSteve ниже (который я еще не тестировал): "Обратите внимание, что ответ IsDesignerHosted был обновлен, чтобы включить LicenseUsage..., так что теперь тест может быть просто, если (IsDesignerHosted). Альтернативный подход проверить LicenseManager в конструкторе и кэшировать результат.
Ответ 2
Почему вы не проверяете LicenseManager.UsageMode.
Это свойство может иметь значения LicenseUsageMode.Runtime или LicenseUsageMode.Designtime.
Вы хотите, чтобы код выполнялся только во время выполнения, используйте следующий код:
if (LicenseManager.UsageMode == LicenseUsageMode.Runtime)
{
bla bla bla...
}
Ответ 3
От эта страница:
( [Изменить 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; Я сомневаюсь, что он пойдет куда угодно, но все равно проголосуйте за него, так как это, очевидно, ошибка (независимо от того, является ли она "по дизайну" ).
Ответ 4
Это метод, который я использую внутри форм:
/// <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
Я использую метод 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
Мы успешно используем этот код:
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";
}
}
Ответ 7
Мое предложение - это оптимизация @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;
}
}
}
Ответ 8
Я никогда не был пойман этим сам, но не мог ли ты просто вернуться к цепочке родителей от элемента управления, чтобы убедиться, что DesignMode установлен где-то выше вас?
Ответ 9
Поскольку ни один из методов не является надежным (DesignMode, LicenseManager) или эффективным (Process, recursive checks), я использую public static bool Runtime { get; private set }
на уровне программы и явно устанавливая его внутри метода Main().
Ответ 10
DesignMode - это частная собственность (из того, что я могу сказать). Ответ заключается в предоставлении публичного имущества, которое предоставляет поддержку DesignMode. Затем вы можете cascasde поддерживать цепочку пользовательских элементов управления до тех пор, пока не столкнетесь с не-пользовательским элементом управления или элементом управления, находящимся в режиме разработки. Что-то вроде этого....
public bool RealDesignMode()
{
if (Parent is MyBaseUserControl)
{
return (DesignMode ? true : (MyBaseUserControl) Parent.RealDesignMode;
}
return DesignMode;
}
Где все ваши UserControls наследуются от MyBaseUserControl. В качестве альтернативы вы можете реализовать интерфейс, предоставляющий "RealDeisgnMode".
Обратите внимание, что этот код не является живым кодом, как раз за пределами манжеты.:)
Ответ 11
Я не понял, что вы не можете назвать Parent.DesignMode(и я тоже кое-что узнал о "protected" на С#)
Здесь есть отражающая версия: (я подозреваю, что может быть преимущество в производительности для создания staticModeProperty статического поля)
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;
}
Ответ 12
Недавно мне пришлось бороться с этой проблемой в 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;
}