带嵌套控件的DesignMode
在开发控件时,是否有人找到针对DesignMode问题的有用解决方案?
问题是,如果我们嵌套控件,则DesignMode仅适用于第一级。第二和较低级别的DesignMode将始终返回FALSE。
标准的技巧是查看正在运行的进程的名称,如果它是" DevEnv.EXE",那么它必须是studio,因此DesignMode确实为TRUE。
这样做的问题是寻找ProcessName会在注册表和其他奇怪的部分中正常工作,最终结果是用户可能没有查看进程名称所需的权限。此外,这条奇怪的路线非常慢。因此,我们不得不堆积更多的骇客才能使用单例,并且如果在询问进程名称时抛出错误,则假定DesignMode为FALSE。
确定DesignMode的一种好方法是按顺序进行的。最终让Microsoft内部对其进行框架修复会更好!
解决方案
回答
我自己从未对此感到迷惑,但是我们难道不能只是从控件中返回父链,看看是否在我们上方的任何位置设置了DesignMode?
回答
DesignMode是一个私有属性(据我所知)。答案是提供一个公开DesignMode属性的公共属性。然后,我们可以级联备份用户控件链,直到遇到非用户控件或者处于设计模式的控件为止。像这样...
public bool RealDesignMode() { if (Parent is MyBaseUserControl) { return (DesignMode ? true : (MyBaseUserControl) Parent.RealDesignMode; } return DesignMode; }
我们所有的UserControl都继承自MyBaseUserControl的位置。或者,我们可以实现一个暴露" RealDeisgnMode"的接口。
请注意,此代码不是实时代码,只是袖手旁观。 :)
回答
我还没有意识到我们不能调用Parent.DesignMode(而且我已经在Ctoo中了解到有关"受保护的"的知识...)
这是一个反射版本:(我怀疑将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; }
回答
为什么不检查LicenseManager.UsageMode。
此属性的值可以为LicenseUsageMode.Runtime或者LicenseUsageMode.Designtime。
我们是否要让代码仅在运行时中运行,请使用以下代码:
if (LicenseManager.UsageMode == LicenseUsageMode.Runtime) { bla bla bla... }
回答
再次讨论这个问题,我现在"发现"了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应用程序),
- 子控件(dll)
- SubSubControl(dll)
然后,我将SubSubControl嵌入SubControl中,然后将其中之一嵌入TestApp.Form中。
此屏幕快照显示了运行时的结果。
此屏幕快照显示了在Visual Studio中打开表单的结果:
结论:似乎没有经过反思,构造函数内唯一可靠的是LicenseUsage,而构造函数外唯一可靠的是'IsDesignedHosted'(由下面的BlueRaja提出)
PS:请参见下面ToolmakerSteve的评论(我尚未测试):"请注意,IsDesignerHosted答案已更新为包含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方法,但是从构造函数缓存值,以在实例的整个生命周期中使用。
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
回答
这是我在表单内部使用的方法:
/// <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属性失败,结果也将是正确的。