¿Alguien ha encontrado una solución útil al problema de DesignMode al desarrollar controles?
El problema es que si anida los controles, DesignMode solo funciona para el primer nivel. El segundo y los niveles inferiores DesignMode siempre devolverán FALSE.
El truco estándar ha sido mirar el nombre del proceso que se está ejecutando y si es "DevEnv.EXE", entonces debe ser estudio, por lo que DesignMode es realmente VERDADERO.
El problema con eso es buscar ProcessName que se abre paso a través del registro y otras partes extrañas con el resultado final de que el usuario podría no tener los derechos necesarios para ver el nombre del proceso. Además esta extraña ruta es muy lenta. Así que hemos tenido que acumular trucos adicionales para usar un singleton y si se produce un error al pedir el nombre del proceso, entonces asuma que DesignMode es FALSE.
Una buena forma limpia de determinar DesignMode está en orden. ¡Hacer que Microsoft lo arregle internamente en el marco sería aún mejor!
fuente
Respuestas:
Revisando esta pregunta, ahora he 'descubierto' 5 formas diferentes de hacer esto, que son las siguientes:
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")) }
Para intentar familiarizarme con las tres soluciones propuestas, creé una pequeña solución de prueba, con tres proyectos:
Luego incrusté el SubSubControl en el SubControl, luego uno de cada uno en el TestApp.Form.
Esta captura de pantalla muestra el resultado cuando se ejecuta.
Esta captura de pantalla muestra el resultado con el formulario abierto en Visual Studio:
Conclusión: Parece que sin reflexión, el único que es confiable dentro del constructor es LicenseUsage, y el único que es confiable fuera del constructor es 'IsDesignedHosted' (por BlueRaja a continuación)
PD: Vea el comentario de ToolmakerSteve a continuación (que no he probado): "Tenga en cuenta que la respuesta de IsDesignerHosted se ha actualizado para incluir LicenseUsage ..., por lo que ahora la prueba puede ser simplemente if (IsDesignerHosted). Un enfoque alternativo es probar LicenseManager en el constructor y almacenar en caché el resultado ".
fuente
if(LicenseUseage == LicenseUsageMode.Designtime || IsDesignerHosted)
sería el enfoque 100% correcto?LicenseUsage...
, por lo que ahora la prueba puede ser simplementeif (IsDesignerHosted)
. Un enfoque alternativo es probar LicenseManager en el constructor y almacenar en caché el resultado .De esta pagina :
( [Editar 2013] Editado para trabajar en constructores, usando el método proporcionado por @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; } }
Envié un informe de error con Microsoft; Dudo que vaya a alguna parte, pero vote a favor de todos modos, ya que obviamente es un error (sea o no "por diseño" ).
fuente
¿Por qué no comprueba LicenseManager.UsageMode? Esta propiedad puede tener los valores LicenseUsageMode.Runtime o LicenseUsageMode.Designtime.
Si desea que el código solo se ejecute en tiempo de ejecución, use el siguiente código:
if (LicenseManager.UsageMode == LicenseUsageMode.Runtime) { bla bla bla... }
fuente
Este es el método que utilizo dentro de los formularios:
/// <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; } }
De esta forma, el resultado será correcto, incluso si fallan las propiedades DesignMode o LicenseManager.
fuente
Utilizo el método LicenseManager, pero almacena en caché el valor del constructor para usarlo durante la vida útil de la instancia.
public MyUserControl() { InitializeComponent(); m_IsInDesignMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime); } private bool m_IsInDesignMode = true; public bool IsInDesignMode { get { return m_IsInDesignMode; } }
Versión 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
fuente
Usamos este código con éxito:
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"; } }
fuente
Mi sugerencia es una optimización de @ BlueRaja-danny-pflughoeft respuesta . Esta solución no calcula el resultado cada vez, sino solo la primera vez (un objeto no puede cambiar UsageMode del diseño al tiempo de ejecución)
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; } } }
fuente
Nunca me ha atrapado esto a mí mismo, pero ¿no podría simplemente volver a subir por la cadena principal desde el control para ver si DesignMode está configurado en algún lugar por encima de usted?
fuente
Dado que ninguno de los métodos es confiable (DesignMode, LicenseManager) o eficiente (proceso, comprobaciones recursivas), estoy usando un
public static bool Runtime { get; private set }
nivel de programa y lo configuro explícitamente dentro del método Main ().fuente
DesignMode es una propiedad privada (por lo que puedo decir). La respuesta es proporcionar una propiedad pública que exponga la propiedad DesignMode. Luego, puede realizar una copia de seguridad en cascada de la cadena de controles de usuario hasta que se encuentre con un control que no sea de usuario o un control que esté en modo de diseño. Algo como esto....
public bool RealDesignMode() { if (Parent is MyBaseUserControl) { return (DesignMode ? true : (MyBaseUserControl) Parent.RealDesignMode; } return DesignMode; }
Donde todos sus UserControls heredan de MyBaseUserControl. Alternativamente, puede implementar una interfaz que exponga el "RealDeisgnMode".
Tenga en cuenta que este código no es un código en vivo, solo reflexiones improvisadas. :)
fuente
No me había dado cuenta de que no se puede llamar a Parent.DesignMode (y también he aprendido algo sobre 'protegido' en C # ...)
Aquí hay una versión reflectante: (sospecho que podría haber una ventaja de rendimiento al hacer de designModeProperty un campo estático)
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; }
fuente
Tuve que luchar contra este problema recientemente en Visual Studio 2017 cuando usaba UserControls anidados. Combino varios de los enfoques mencionados anteriormente y en otros lugares, luego modifiqué el código hasta que tuve un método de extensión decente que funciona aceptablemente hasta ahora. Realiza una secuencia de comprobaciones, almacenando el resultado en variables booleanas estáticas, por lo que cada comprobación solo se realiza como máximo una vez en tiempo de ejecución. El proceso puede ser excesivo, pero evita que el código se ejecute en Studio. Espero que esto ayude a alguien.
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; }
fuente