Czy ktoś znalazł przydatne rozwiązanie problemu DesignMode podczas tworzenia kontrolek?
Problem polega na tym, że jeśli zagnieżdżasz kontrolki, DesignMode działa tylko na pierwszym poziomie. Drugi i niższy poziom DesignMode zawsze zwróci FALSE.
Standardowy hack polegał na sprawdzeniu nazwy uruchomionego procesu i jeśli jest to „DevEnv.EXE”, to musi to być studio, więc DesignMode jest naprawdę TRUE.
Problem z wyszukiwaniem nazwy procesu przebiega przez rejestr i inne dziwne części, w wyniku czego użytkownik może nie mieć wymaganych uprawnień do wyświetlania nazwy procesu. W dodatku ta dziwna trasa jest bardzo powolna. Musieliśmy więc zebrać dodatkowe hacki, aby użyć singletona, a jeśli podczas pytania o nazwę procesu zostanie wyrzucony błąd, załóżmy, że DesignMode ma wartość FALSE.
Dobry, czysty sposób określenia DesignMode jest w porządku. Faktyczne przekonanie Microsoftu do wewnętrznego naprawienia tego frameworka byłoby jeszcze lepsze!
źródło
Odpowiedzi:
Wracając do tego pytania, teraz `` odkryłem '' 5 różnych sposobów na zrobienie tego, które są następujące:
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")) }
Aby spróbować zrozumieć trzy proponowane rozwiązania, stworzyłem małe rozwiązanie testowe - z trzema projektami:
Następnie osadziłem SubSubControl w SubControl, a następnie po jednym w TestApp.Form.
Ten zrzut ekranu przedstawia wynik po uruchomieniu.
Ten zrzut ekranu przedstawia wynik z formularzem otwartym w programie Visual Studio:
Wniosek: wydawałoby się, że bez refleksji jedynym niezawodnym w konstruktorze jest LicenseUsage, a jedynym niezawodnym poza konstruktorem jest „IsDesignedHosted” ( poniżej BlueRaja )
PS: Zobacz komentarz ToolmakerSteve poniżej (którego nie testowałem): „Zwróć uwagę, że odpowiedź IsDesignerHosted została zaktualizowana i obejmuje LicenseUsage…, więc teraz test może być po prostu if (IsDesignerHosted). Alternatywnym podejściem jest test LicenseManager w konstruktorze i zapisz wynik w pamięci podręcznej . "
źródło
if(LicenseUseage == LicenseUsageMode.Designtime || IsDesignerHosted)
byłoby w 100% poprawnym podejściem?LicenseUsage...
, więc teraz test może być po prostuif (IsDesignerHosted)
. Alternatywnym podejściem jest przetestowanie LicenseManager w konstruktorze i buforowanie wyniku .Z tej strony :
( [Edytuj 2013] Edytowane do pracy w konstruktorach, przy użyciu metody dostarczonej przez @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; } }
Mam złożony bug-raport z Microsoft; Wątpię, czy coś pójdzie gdziekolwiek, ale i tak zagłosuj na to, ponieważ jest to oczywiście błąd (niezależnie od tego, czy jest to „ zgodne z projektem” ).
źródło
Dlaczego nie sprawdzisz LicenseManager.UsageMode. Ta właściwość może mieć wartości LicenseUsageMode.Runtime lub LicenseUsageMode.Designtime.
Jeśli chcesz, aby kod działał tylko w czasie wykonywania, użyj następującego kodu:
if (LicenseManager.UsageMode == LicenseUsageMode.Runtime) { bla bla bla... }
źródło
Oto metoda, której używam wewnątrz formularzy:
/// <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; } }
W ten sposób wynik będzie poprawny, nawet jeśli zawodzi jedna z właściwości DesignMode lub LicenseManager.
źródło
Używam metody LicenseManager, ale buforuję wartość z konstruktora do użytku przez cały okres istnienia instancji.
public MyUserControl() { InitializeComponent(); m_IsInDesignMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime); } private bool m_IsInDesignMode = true; public bool IsInDesignMode { get { return m_IsInDesignMode; } }
Wersja 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
źródło
Używamy tego kodu z powodzeniem:
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"; } }
źródło
Moja sugestia jest optymalizacja @ blueraja-danny-pflughoeft odpowiedzi . To rozwiązanie nie oblicza wyniku za każdym razem, ale tylko za pierwszym razem (obiekt nie może zmienić UsageMode z projektu na środowisko uruchomieniowe)
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; } } }
źródło
Sam nigdy nie zostałem przez to złapany, ale czy nie mógłbyś po prostu przejść z powrotem do łańcucha nadrzędnego z kontrolki, aby sprawdzić, czy DesignMode jest ustawiony gdzieś nad tobą?
źródło
Ponieważ żadna z metod nie jest niezawodna (DesignMode, LicenseManager) ani wydajna (proces, kontrole rekurencyjne), używam
public static bool Runtime { get; private set }
na poziomie programu i jawnie ustawiam ją w metodzie Main ().źródło
DesignMode jest własnością prywatną (z tego, co wiem). Odpowiedzią jest podanie właściwości publicznej, która uwidacznia właściwość DesignMode. Następnie można kaskadowo tworzyć kopię zapasową łańcucha kontrolek użytkownika, aż napotkasz kontrolkę niebędącą użytkownikiem lub kontrolkę, która jest w trybie projektowania. Coś takiego....
public bool RealDesignMode() { if (Parent is MyBaseUserControl) { return (DesignMode ? true : (MyBaseUserControl) Parent.RealDesignMode; } return DesignMode; }
Gdzie wszystkie Twoje UserControls dziedziczą po MyBaseUserControl. Alternatywnie możesz zaimplementować interfejs, który ujawnia "RealDeisgnMode".
Należy pamiętać, że ten kod nie jest kodem na żywo, tylko z zamyślenia mankietu. :)
źródło
Nie zdawałem sobie sprawy, że nie można wywołać Parent.DesignMode (i dowiedziałem się też czegoś o 'protected' w C # ...)
Oto wersja odblaskowa: (podejrzewam, że uczynienie designModeProperty polem statycznym może mieć przewagę w wydajności)
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; }
źródło
Musiałem ostatnio walczyć z tym problemem w programie Visual Studio 2017 podczas korzystania z zagnieżdżonych UserControls. Łączę kilka podejść wspomnianych powyżej i gdzie indziej, a następnie poprawiałem kod, aż uzyskałem przyzwoitą metodę rozszerzenia, która działa do tej pory akceptowalnie. Wykonuje sekwencję sprawdzeń, przechowując wynik w statycznych zmiennych boolowskich, więc każde sprawdzenie jest wykonywane najwyżej tylko raz w czasie wykonywania. Ten proces może być przesadą, ale uniemożliwia wykonanie kodu w studio. Mam nadzieję, że to komuś pomoże.
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; }
źródło