当我在 Visual Studio 的设计器中打开 Windows 窗体窗体时,我的代码中出现了一些错误。如果表单是由设计师打开的,我想在我的代码中分支并执行不同的初始化,而不是真正运行它。
如何在运行时确定代码是否作为设计器打开表单的一部分执行?
当我在 Visual Studio 的设计器中打开 Windows 窗体窗体时,我的代码中出现了一些错误。如果表单是由设计师打开的,我想在我的代码中分支并执行不同的初始化,而不是真正运行它。
如何在运行时确定代码是否作为设计器打开表单的一部分执行?
要确定您是否处于“设计模式”:
if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
{
// Design time logic
}
Control.DesignMode 属性可能是您正在寻找的。它告诉您控件的父控件是否在设计器中打开。
在大多数情况下,它工作得很好,但在某些情况下它不能按预期工作。首先,它在控件构造函数中不起作用。其次,“孙子”控件的 DesignMode 为 false。例如,当 UserControl 承载在父级中时,承载在 UserControl 中的控件上的 DesignMode 将返回 false。
有一个非常简单的解决方法。它是这样的:
public bool HostedDesignMode
{
get
{
Control parent = Parent;
while (parent!=null)
{
if(parent.DesignMode) return true;
parent = parent.Parent;
}
return DesignMode;
}
}
我还没有测试过该代码,但它应该可以工作。
最可靠的方法是:
public bool isInDesignMode
{
get
{
System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
bool res = process.ProcessName == "devenv";
process.Dispose();
return res;
}
}
最可靠的方法是忽略 DesignMode 属性并使用您自己在应用程序启动时设置的标志。
班级:
public static class Foo
{
public static bool IsApplicationRunning { get; set; }
}
程序.cs:
[STAThread]
static void Main()
{
Foo.IsApplicationRunning = true;
// ... code goes here ...
}
然后只需在需要时检查标志。
if(Foo.IsApplicationRunning)
{
// Do runtime stuff
}
else
{
// Do design time stuff
}
我在 Visual Studio Express 2013 中遇到了同样的问题。我尝试了这里建议的许多解决方案,但对我有用的是另一个线程的答案,如果链接断开,我将在此处重复:
protected static bool IsInDesigner
{
get { return (Assembly.GetEntryAssembly() == null); }
}
devenv 方法在 VS2012 中停止工作,因为设计器现在有自己的进程。这是我目前正在使用的解决方案('devenv' 部分留在那里留作遗留,但没有 VS2010 我无法测试它)。
private static readonly string[] _designerProcessNames = new[] { "xdesproc", "devenv" };
private static bool? _runningFromVisualStudioDesigner = null;
public static bool RunningFromVisualStudioDesigner
{
get
{
if (!_runningFromVisualStudioDesigner.HasValue)
{
using (System.Diagnostics.Process currentProcess = System.Diagnostics.Process.GetCurrentProcess())
{
_runningFromVisualStudioDesigner = _designerProcessNames.Contains(currentProcess.ProcessName.ToLower().Trim());
}
}
return _runningFromVisualStudioDesigner.Value;
}
}
/// <summary>
/// Are we in design mode?
/// </summary>
/// <returns>True if in design mode</returns>
private bool IsDesignMode() {
// Ugly hack, but it works in every version
return 0 == String.CompareOrdinal(
"devenv.exe", 0,
Application.ExecutablePath, Application.ExecutablePath.Length - 10, 10);
}
System.Diagnostics.Debugger.IsAttached
这是 hack-ish,但如果您使用的是VB.NET,并且当您在 Visual Studio 中运行时,My.Application.Deployment.CurrentDeployment将是 Nothing,因为您还没有部署它。我不确定如何检查 C# 中的等效值。
using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess())
{
bool inDesigner = process.ProcessName.ToLower().Trim() == "devenv";
return inDesigner;
}
我尝试了上面的代码(添加了一个 using 语句),这在某些情况下对我来说会失败。在直接放置在表单中的用户控件的构造函数中进行测试,并在启动时加载设计器。但会在其他地方工作。
在所有地点对我有用的是:
private bool isDesignMode()
{
bool bProcCheck = false;
using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess())
{
bProcCheck = process.ProcessName.ToLower().Trim() == "devenv";
}
bool bModeCheck = (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime);
return bProcCheck || DesignMode || bModeCheck;
}
也许有点矫枉过正,但它有效,所以对我来说已经足够了。
上面提到的例子中成功的是bModeCheck,所以很可能DesignMode是多余的。
我不确定在调试模式下运行是否算作真实,但一种简单的方法是if
在代码中包含一个检查System.Diagnostics.Debugger.IsAttached
.
您检查DesignMode
控件的属性:
if (!DesignMode)
{
//Do production runtime stuff
}
请注意,这在您的构造函数中不起作用,因为组件尚未初始化。
我们在 UserControls 中使用以下代码,它可以完成工作。正如其他成员所指出的那样,仅使用 DesignMode 在使用您的自定义用户控件的应用程序中不起作用。
public bool IsDesignerHosted
{
get { return IsControlDesignerHosted(this); }
}
public bool IsControlDesignerHosted(System.Windows.Forms.Control ctrl)
{
if (ctrl != null)
{
if (ctrl.Site != null)
{
if (ctrl.Site.DesignMode == true)
return true;
else
{
if (IsControlDesignerHosted(ctrl.Parent))
return true;
else
return false;
}
}
else
{
if (IsControlDesignerHosted(ctrl.Parent))
return true;
else
return false;
}
}
else
return false;
}
基本上上面的逻辑归结为:
public bool IsControlDesignerHosted(System.Windows.Forms.Control ctrl)
{
if (ctrl == null) return false;
if (ctrl.Site != null && ctrl.Site.DesignMode) return true;
return IsControlDesignerHosted(ctrl.Parent);
}
运行项目时,其名称会附加“.vshost”。
所以,我用这个:
public bool IsInDesignMode
{
get
{
Process p = Process.GetCurrentProcess();
bool result = false;
if (p.ProcessName.ToLower().Trim().IndexOf("vshost") != -1)
result = true;
p.Dispose();
return result;
}
}
这个对我有用。
如果您在设计时创建了根本不需要的属性,则可以使用DesignerSerializationVisibility属性并将其设置为 Hidden。例如:
protected virtual DataGridView GetGrid()
{
throw new NotImplementedException("frmBase.GetGrid()");
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int ColumnCount { get { return GetGrid().Columns.Count; } set { /*Some code*/ } }
每次我更改表单NotImplementedException()
并尝试保存时,它都会阻止我的 Visual Studio 崩溃。相反,Visual Studio 知道我不想序列化这个属性,所以它可以跳过它。它只在表单的属性框中显示一些奇怪的字符串,但忽略它似乎是安全的。
请注意,此更改在您重建之前不会生效。
如果您在窗体或控件中,则可以使用 DesignMode 属性:
if (DesignMode)
{
DesignMode Only stuff
}
System.ComponentModel.Component.DesignMode == true
我发现 DesignMode 属性有问题,至少在以前版本的 Visual Studio 中是这样。因此,我使用以下逻辑制作了自己的:
Process.GetCurrentProcess().ProcessName.ToLower().Trim() == "devenv";
我知道,这是一种 hack,但效果很好。
为了解决这个问题,您还可以编写如下代码:
private bool IsUnderDevelopment
{
get
{
System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
if (process.ProcessName.EndsWith(".vshost")) return true;
else return false;
}
}
这是另一个:
//Caters only to thing done while only in design mode
if (App.Current.MainWindow == null){ // in design mode }
//Avoids design mode problems
if (App.Current.MainWindow != null) { //applicaiton is running }
在这里测试了大部分答案之后,不幸的是,对我来说没有任何效果(VS2015)。因此,我在JohnV 的答案中添加了一些改动,但它并没有开箱即用,因为 DesignMode 是 Control 类中的受保护属性。
首先我做了一个扩展方法,它通过反射返回 DesignMode 的属性值:
public static Boolean GetDesignMode(this Control control)
{
BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static;
PropertyInfo prop = control.GetType().GetProperty("DesignMode", bindFlags);
return (Boolean)prop.GetValue(control, null);
}
然后我做了一个像JohnV这样的函数:
public bool HostedDesignMode
{
get
{
Control parent = Parent;
while (parent != null)
{
if (parent.GetDesignMode()) return true;
parent = parent.Parent;
}
return DesignMode;
}
}
这是唯一对我有用的方法,避免了所有的 ProcessName 混乱,虽然不应该轻易使用反射,但在这种情况下,它起到了很大的作用!;)
编辑:
您还可以使第二个函数成为这样的扩展方法:
public static Boolean IsInDesignMode(this Control control)
{
Control parent = control.Parent;
while (parent != null)
{
if (parent.GetDesignMode())
{
return true;
}
parent = parent.Parent;
}
return control.GetDesignMode();
}
/// <summary>
/// Whether or not we are being run from the Visual Studio IDE
/// </summary>
public bool InIDE
{
get
{
return Process.GetCurrentProcess().ProcessName.ToLower().Trim().EndsWith("vshost");
}
}
这是一种灵活的方式,可以适应您从哪里编译以及您是否关心您所处的模式。
string testString1 = "\\bin\\";
//string testString = "\\bin\\Debug\\";
//string testString = "\\bin\\Release\\";
if (AppDomain.CurrentDomain.BaseDirectory.Contains(testString))
{
//Your code here
}