如何判断.NET代码是否由Visual Studiodevise器运行
当我在Visual Studio的devise器中打开Windows窗体表单时,出现了一些在我的代码中引发的错误。 我想分支我的代码,并执行一个不同的初始化,如果表单被打开的devise师,而不是如果它是真正的运行。
如何在运行时确定代码是否作为devise者打开表单的一部分而被执行?
要了解您是否处于“devise模式”:
- Windows窗体组件(和控件)具有DesignMode属性。
- Windows Presentation Foundation控件应使用IsInDesignMode附加属性。
if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime) { // Design time logic }
Control.DesignMode属性可能是你正在寻找的。 它会告诉您控件的父项是否在devise器中打开。
在大多数情况下,它的效果很好,但有些情况下它不能按预期工作。 首先,它在控件构造函数中不起作用。 其次,DesignMode对于“孙子”控制是错误的。 例如,UserControl中托pipe的控件上的DesignMode将在UserControl托pipe在父项中时返回false。
有一个相当简单的解决方法。 它是这样的:
public bool HostedDesignMode { get { Control parent = Parent; while (parent!=null) { if(parent.DesignMode) return true; parent = parent.Parent; } return DesignMode; } }
我没有testing过这个代码,但它应该可以工作。
最可靠的方法是:
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; } }
Program.cs中:
[STAThread] static void Main() { Foo.IsApplicationRunning = true; // ... code goes here ... }
然后只需检查标志,你需要它。
if(Foo.IsApplicationRunning) { // Do runtime stuff } else { // Do design time stuff }
由于devise师现在有自己的过程,devenv方法停止在VS2012工作。 这里是我目前使用的解决scheme(“devenv”部分留在那里的遗留,但没有VS2010我不能够testing,虽然) 。
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; } }
using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess()) { bool inDesigner = process.ProcessName.ToLower().Trim() == "devenv"; return inDesigner; }
我尝试了上面的代码(添加了使用语句),这在某些情况下会失败。 在一个用户控件的构造函数中进行testing,并在启动时加载devise器,直接放置在一个表单中。 但会在其他地方工作。
对我来说,在所有地方工作的是:
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可能是多余的。
/// <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); }
我在Visual Studio Express 2013中遇到了同样的问题。我尝试了很多这里提出的解决scheme,但是为我工作的解决scheme是一个不同线程的答案,在链接被破坏的情况下,
protected static bool IsInDesigner { get { return (Assembly.GetEntryAssembly() == null); } }
System.Diagnostics.Debugger.IsAttached
我不确定在debugging模式下运行是否真实,但是一个简单的方法是在代码中包含一个if
语句来检查System.Diagnostics.Debugger.IsAttached
。
我们在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; }
您检查控件的DesignMode
属性:
if (!DesignMode) { //Do production runtime stuff }
请注意,这不会在你的构造函数中工作,因为组件还没有被初始化。
System.ComponentModel.Component.DesignMode == true
运行项目时,其名称会附加“.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; } }
这个对我有用。
这是hack-ish,但是如果你使用的是VB.NET ,当你在Visual Studio中运行时My.Application.Deployment.CurrentDeployment将是Nothing,因为你还没有部署它。 我不知道如何检查在C#中的等效值。
如果创build了一个在devise时根本不需要的属性,则可以使用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*/ } }
它停止了我的Visual Studio崩溃每次我用NotImplementedException()
更改窗体,并试图保存。 相反,Visual Studio知道我不想序列化这个属性,所以它可以跳过它。 它只在窗体的属性框中显示一些奇怪的string,但似乎是安全的忽略。
请注意,此更改在重build之前不会生效。
如果您处于窗体或控件中,则可以使用DesignMode属性:
if (DesignMode) { DesignMode Only stuff }
我发现DesignMode属性是buggy,至less在以前的Visual Studio版本中。 因此,我用自己的逻辑做了自己的事情:
Process.GetCurrentProcess().ProcessName.ToLower().Trim() == "devenv";
我知道这是一种黑客行为,但效果很好。
要解决这个问题,你也可以编码如下:
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 }
在testing了大部分答案之后,很遗憾没有为我工作(VS2015)。 所以我在JohnV的答案中增加了一点小小的改动 ,因为DesignMode是Control类中的一个受保护的属性。
首先我做了一个扩展方法,它通过reflection返回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的function:
public bool HostedDesignMode { get { Control parent = Parent; while (parent != null) { if (parent.GetDesignMode()) return true; parent = parent.Parent; } return DesignMode; } }
这是为我工作的唯一方法,避免了所有的ProcessName混乱,而reflection不应该被轻率使用,在这种情况下,它做了所有的区别! ;)
编辑:
你也可以使第二个函数成为这样的扩展方法:
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 }