.NET Windows Forms设计时间规则

我有一个对象启动一个线程,打开一个文件,并等待来自其他类的输入。 在接收输入时,它将其写入磁盘。 基本上,它是一个线程安全的数据记录类……

这是奇怪的部分。 当我在设计器(Visual Studio 2008)中打开一个使用该对象的表单时,将创建该文件。 它显然是在设计时vhost进程下运行的……

奇怪的是我无法在另一个项目中重现这个问题。 我不确定在设计器中执行的代码和没有执行的代码的规则是什么。 例如,在Windows窗体构造函数中创建文件实际上并不是在设计时创建文件…

解释是什么? 有参考吗?

您可以检查LicenseManager的UsageMode,以检查代码是否在设计时间内。

System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime

这是一个简单的例子:

using System; using System.ComponentModel; using System.Windows.Forms; namespace Test { public class ComponentClass : Component { public ComponentClass() { MessageBox.Show("Runtime!"); } } } 

当此组件在设计器中添加到您的表单时,您将立即获得一个消息框。

为了防止这种情况,您可以添加一个简单的if语句来检查代码是否不在设计时

 using System; using System.ComponentModel; using System.Windows.Forms; namespace Test { public class ComponentClass : Component { public ComponentClass() { if (LicenseManager.UsageMode != LicenseUsageMode.Designtime) { MessageBox.Show("Runtime!"); } } } } 

添加if语句后,通过设计器将组件添加到表单时,不再显示消息框。

我希望这有帮助。

-jeremy

在设计器中编辑该类时,控件或表单的构造函数不会被执行(OnLoad也不会被调用)。 我偶尔使用它在设计器中设置一个值(例如,使其子控件在设计器中都是可见的),但是将它们中的一些重写为构造函数中的不同默认值(例如,隐藏某些仅显示的子控件)在某些情况下,例如状态栏上的指示器)。

但是,如果将控件作为子项放置在设计器中的另一个控件或窗体上,则构造函数会执行。 OnLoad也被执行了。 这可能是您的日志记录代码在设计器中意外触发的方式。

为了检测设计与运行时间, 另一个问题 的答案有一些经验测试的屏幕截图,显示了一些常见方法返回的值。 看起来设计器中正在编辑的表单或控件的子控件(两级向下)的子控件看到自己的DesignMode == false,因此正常的属性检查将无法保护代码(例如,在OnLoad方法中) )嵌套在设计器中添加的控件中的控件。 如果您按照预期检查DesignMode,则可能是嵌套导致它绕过该检查。 它也始终在构造函数中看到DesignMode == false。

另请注意,LicenseManager.UsageMode检查在构造函数中看到DesignTime; 当调用OnLoad时,它位于RunTime LicenseContext中。 最完整的解决方案似乎是检查控件或表单(或组件)的构造函数中的LicenseManager.UsageMode,并将设置保存到成员变量或属性,稍后可以检查以避免运行永远不会在设计器中运行的代码甚至在嵌套时。 在另一个问题的另一个答案中还有另一种方法可以解释嵌套,但只能在构造函数之外工作。

好吧,既然这已经复活了,这里是我用来确定我是否处于设计模式的函数:

 public static bool IsAnyInDesignMode(Control control){ while(control != null){ if(control.Site != null && control.Site.DesignMode) return true; control = control.Parent; } return false; } 

这处理控件是由另一个控件创建的子控件的情况。 DesignMode属性仅为设计者自己创建的控件设置。

您还可以使用它来检查Visual Studio Designer是否正在运行代码:

 public static bool DesignMode { get { return (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv"); } } 

然后在Form_Load中:

 if (!DesignMode) { // Run code that breaks in Visual Studio Designer (like trying to get a DB connection) } 

但是,这不如使用LicensManager.UsageMode那么优雅,但它可以工作(直到Microsoft更改Visual Studio运行的进程的名称)。

有一些事情你不应该与设计师做。 我没有任何确凿的证据,但我发现当你从中取走默认构造函数时,Windows窗体设计师讨厌它。 继续前进并创建新的重载,但保留空构造函数。

还要尽量避免在inheritance的基类中执行Form_Load事件。