问题
I have an object that starts a thread, opens a file, and waits for input from other classes. As it receives input, it writes it to disk. Basically, it's a thread safe data logging class...
Here's the weird part. When I open a form in the designer (Visual Studio 2008) that uses the object the file gets created. It's obviously running under the design time vhost process...
The odd thing is I've not been able to reproduce the issue in another project. I'm not sure what the rules are for code that gets executed in the designer and code that does not. For example, creating a file in a Windows Forms constructor doesn't actually create the file at design time...
What is the explanation? Is there a reference?
回答1:
You can check the UsageMode of the LicenseManager, to check if the code is in design time or not.
System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime
Here is a quick example:
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace Test
{
public class ComponentClass : Component
{
public ComponentClass()
{
MessageBox.Show("Runtime!");
}
}
}
When this component gets add to your form in the designer, you will immediatly get a message box.
To prevent this you can add a simple if statement to check if the code is not in design time
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!");
}
}
}
}
After adding the if statement, the messagebox no longer appears when the component is added to the form via the designer.
I hope this helps.
-jeremy
回答2:
The constructor of a control or form does not get executed when editing that class in the designer (nor does OnLoad get called). I've occasionally used this to set one value in the designer (eg. making its child controls all Visible in the designer) but override some of them to a different default value in the constructor (eg. hiding certain child controls which will only show in certain circumstances, such as an indicator on a status bar).
However, the constructor does get executed if the control is placed as a child on another control or form in the designer. OnLoad gets executed as well. This may be how your logging code was getting accidentally triggered in the designer.
For detecting design vs runtime, an answer to another question has screenshots of some emperical tests showing the values returned by some common approaches. It appears that a child control of a child control (two levels down) of the form or control being edited in the designer sees its own DesignMode == false, so the normal property check will fail to protect code (eg. in the OnLoad method) for controls nested within a control added in the designer. If you were checking DesignMode as one would expect, it could be the nesting which caused it to get around that check. It also always sees DesignMode == false within the constructor.
Also, note that the LicenseManager.UsageMode check only sees DesignTime within the constructor; when OnLoad is called it is within a RunTime LicenseContext. The most complete solution seems to be to check LicenseManager.UsageMode in the constructor of the control or form (or component) and save the setting to a member variable or property which you can check later to avoid running code that should never run in the designer even when nested. There's also another approach in another answer to that other question which accounts for nesting but only works outside the constructor.
回答3:
Well, since this has been resurrected anyway, here's the function I use to determine whether I'm in design mode:
public static bool IsAnyInDesignMode(Control control){
while(control != null){
if(control.Site != null && control.Site.DesignMode)
return true;
control = control.Parent;
}
return false;
}
This handles the case where the control is a child created by another control. The DesignMode
property is only set for controls created by the designer itself.
回答4:
You could also use this to check if the Visual Studio Designer is running the code:
public static bool DesignMode
{
get { return (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv"); }
}
Then in Form_Load:
if (!DesignMode)
{
// Run code that breaks in Visual Studio Designer (like trying to get a DB connection)
}
However, this is less elegant than using the LicensManager.UsageMode
, but it works (until Microsoft changes the name of the process Visual Studio runs under).
回答5:
There are some things you shouldn't do with the designer. I don't have any hard evidence, but I found that the Windows Forms designer hates it when you take away the default constructor from it. Just go ahead and create new overloads, but leave the empty constructor in place.
Also try to avoid doing Form_Load
events in base classes you inherit from.
来源:https://stackoverflow.com/questions/282014/net-windows-forms-design-time-rules