具有嵌套控件的DesignMode
有没有人在开发控件时发现DesignMode问题的一个有用的解决scheme?
问题是,如果您嵌套控件,DesignMode只适用于第一级。 第二个和更低级别的DesignMode将始终返回FALSE。
标准黑客一直在查看正在运行的进程的名称,如果它是“DevEnv.EXE”,那么它必须是工作室,因此DesignMode真的是真的。
与此相关的问题是寻找ProcessName通过registry和其他奇怪的部分,最终的结果是用户可能没有看到进程名称所需的权限。 另外这个奇怪的路线很慢。 所以我们不得不另外使用一个单例来处理,如果在询问进程名时抛出一个错误,那么假设DesignMode是FALSE。
一个很好的干净的方式来确定DesignMode是为了。 通过让微软在内部修复这个框架会更好!
重温这个问题,我现在已经“发现”了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")) }
为了试图解决所提出的三个解决scheme,我创build了一个小testing解决scheme – 有三个项目:
- TestApp(winforms应用程序),
- SubControl(dll)
- SubSubControl(dll)
然后,我将SubSubControlembedded到SubControl中,然后在TestApp.Form中embedded其中的一个。
该屏幕截图显示了运行时的结果。
该屏幕截图显示了在Visual Studio中打开窗体的结果:
结论:似乎没有reflection , 在构造函数中唯一可靠的是LicenseUsage,唯一在构造函数之外可靠的是'IsDesignedHosted'(由BlueRaja在下面)
PS:请参阅下面的ToolmakerSteve的评论(我还没有testing过):“请注意, IsDesignerHosted的答案已经更新,包括LicenseUsage …,所以现在testing可以简单地是如果(IsDesignerHosted)。另一种方法是testingLicenseManager的构造并caching结果 。“
你为什么不检查LicenseManager.UsageMode。 该属性可以具有值LicenseUsageMode.Runtime或LicenseUsageMode.Designtime。
你想让代码只在运行时运行,使用下面的代码:
if (LicenseManager.UsageMode == LicenseUsageMode.Runtime) { bla bla bla... }
从这个页面 :
( [编辑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; } }
我已经向微软提交了一个错误报告 。 我怀疑它会去哪里,但无论如何投票,因为这显然是一个错误(无论是否是“devise” )。
这是我在表格中使用的方法:
/// <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属性都失败,结果也是正确的。
我们用这个代码成功:
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"; } }
我的build议是@ blueraja-danny-pflughoeft 回复的优化。 此解决scheme不会每次都计算结果,但仅在第一次(对象无法将UsageMode从devise更改为运行时)
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; } } }
我使用LicenseManager方法,但caching来自构造函数的值,以便在实例的整个生命周期中使用。
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
我从来没有被这个自己抓住过,但是你能不能从控制器上回溯到Parent链,看看DesignMode是否设置在你的上面?
DesignMode是一个私有财产(从我可以告诉)。 答案是提供一个暴露DesignMode prop的公共属性。 然后,您可以重新链接用户控件链,直到遇到非用户控件或处于devise模式的控件。 像这样的东西….
public bool RealDesignMode() { if (Parent is MyBaseUserControl) { return (DesignMode ? true : (MyBaseUserControl) Parent.RealDesignMode; } return DesignMode; }
你所有的用户控件inheritance自MyBaseUserControl。 或者你可以实现一个暴露“RealDeisgnMode”的接口。
请注意,此代码不是实时代码,只是在袖口沉思。 🙂
我还没有意识到,你不能调用Parent.DesignMode(我也学习了一些关于在C#中的“保护”…)
这里是一个reflection版本:(我怀疑可能有一个性能优势,使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; }
由于没有任何方法是可靠的(DesignMode,LicenseManager)或高效的(进程,recursion检查)我使用的是一个public static bool Runtime { get; private set }
public static bool Runtime { get; private set }
,并在Main()方法中明确地设置它。