如何判断Visual Studio设计器是否正在运行.NET代码

如何判断Visual Studio设计器是否正在运行.NET代码

How to tell if .NET code is being run by Visual Studio designer

在Visual Studio设计器中打开Windows窗体窗体时,我的代码中引发了一些错误。 如果设计者正在打开窗体,而实际运行时,我想分支代码并执行不同的初始化。

如何在运行时确定是否在设计者打开表单的过程中执行了代码?


要了解您是否处于"设计模式":

  • Windows Forms组件(和控件)具有DesignMode属性。
  • Windows Presentation Foundation控件应使用IsInDesignMode附加属性。

1
2
3
4
if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
{
  // Design time logic
}

Control.DesignMode属性可能是您要寻找的。它告诉您控件的父级是否在设计器中打开。

在大多数情况下,它工作得很好,但是在某些情况下,它并没有达到预期的效果。首先,它在控件构造函数中不起作用。其次,对于"孙子"控件,DesignMode为false。例如,当UserControl托管在父级中时,UserControl托管的控件上的DesignMode将返回false。

有一个非常简单的解决方法。它是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
public bool HostedDesignMode
{
  get
  {
     Control parent = Parent;
     while (parent!=null)
     {
        if(parent.DesignMode) return true;
        parent = parent.Parent;
     }
     return DesignMode;
  }
}

我没有测试过该代码,但它应该可以工作。


最可靠的方法是:

1
2
3
4
5
6
7
8
9
10
public bool isInDesignMode
{
    get
    {
        System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
        bool res = process.ProcessName =="devenv";
        process.Dispose();
        return res;
    }
}

最可靠的方法是忽略DesignMode属性,并使用在应用程序启动时设置的自己的标志。

类:

1
2
3
4
public static class Foo
{
    public static bool IsApplicationRunning { get; set; }
}

Program.cs:

1
2
3
4
5
6
[STAThread]
static void Main()
{
     Foo.IsApplicationRunning = true;
     // ... code goes here ...
}

然后,只要有需要,请检查该标志。

1
2
3
4
5
6
7
8
if(Foo.IsApplicationRunning)
{
    // Do runtime stuff
}
else
{
    // Do design time stuff
}

我在Visual Studio Express 2013中遇到了相同的问题。我尝试了此处建议的许多解决方案,但对我有用的解决方案是对其他线程的解答,如果链接断开,我将在这里重复:

1
2
3
4
protected static bool IsInDesigner
{
    get { return (Assembly.GetEntryAssembly() == null); }
}


由于设计人员现在拥有自己的流程,因此devenv方法在VS2012中停止工作。这是我当前正在使用的解决方案(" devenv"部分保留了下来,但是如果没有VS2010,我将无法对其进行测试)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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;
  }
}

1
2
3
4
5
6
7
8
9
10
/// <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);
}

这有点骇人听闻,但是如果您使用的是VB.NET,并且在Visual Studio中运行时,My.Application.Deployment.CurrentDeployment将为Nothing,因为您尚未进行部署。我不确定如何检查C#中的等效值。


1
System.Diagnostics.Debugger.IsAttached

1
2
3
4
5
using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess())
{
    bool inDesigner = process.ProcessName.ToLower().Trim() =="devenv";
    return inDesigner;
}

我尝试了上面的代码(添加了一条using语句),这对我来说有时会失败。在启动时加载设计器的情况下,直接将用户控件的构造器中的测试放置在窗体中。但是会在其他地方工作。

在所有位置对我有用的是:

1
2
3
4
5
6
7
8
9
10
11
12
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;
}

也许有点矫kill过正,但它确实有效,对我来说足够了。

上面提到的示例中的成功是bModeCheck,因此DesignMode可能是多余的。


运行项目时,其名称后会附加" .vshost"。

所以,我用这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    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属性并将其设置为"隐藏"。例如:

1
2
3
4
5
6
7
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属性:

1
2
3
4
if (!DesignMode)
{
//Do production runtime stuff
}

请注意,这在您的构造函数中将不起作用,因为尚未初始化组件。


我不确定在调试模式下运行是否是真实的,但是一种简单的方法是在代码中包含一个if语句,以检查System.Diagnostics.Debugger.IsAttached


我们在UserControls中使用以下代码,即可完成工作。如其他成员所指出的那样,仅使用DesignMode在使用自定义用户控件的应用中将不起作用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    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;
    }

基本上,以上逻辑可归结为:

1
2
3
4
5
6
    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);
    }

在测试完此处的大多数答案后,很遗憾,没有任何结果适用于我(VS2015)。
因此,我为JohnV的答案增加了一点点转折,因为DesignMode是Control类中的一个受保护的Property,所??以它开箱即用。

首先,我做了一个扩展方法,该方法通过反射返回DesignMode的Property值:

1
2
3
4
5
6
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的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
public bool HostedDesignMode
{
    get
    {
        Control parent = Parent;
        while (parent != null)
        {
            if (parent.GetDesignMode()) return true;
            parent = parent.Parent;
        }
        return DesignMode;
    }
}

这是唯一对我有用的方法,避免了所有ProcessName混乱,并且尽管不应轻易使用反射,但在这种情况下,它起到了很大的作用! ;)

编辑:

您还可以将第二个功能作为扩展方法,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
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();
}

我发现DesignMode属性存在漏洞,至少在Visual Studio的早期版本中是如此。因此,我使用以下逻辑制作了自己的作品:

1
Process.GetCurrentProcess().ProcessName.ToLower().Trim() =="devenv";

我知道这有点骇人听闻,但效果很好。


这是另一个:

1
2
3
4
5
        //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 }

1
System.ComponentModel.Component.DesignMode == true

如果您使用的是表单或控件,则可以使用DesignMode属性:

1
2
3
4
if (DesignMode)
{
        DesignMode Only stuff
}

要解决该问题,您还可以编写以下代码:

1
2
3
4
5
6
7
8
9
10
private bool IsUnderDevelopment
{
    get
    {
        System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
        if (process.ProcessName.EndsWith(".vshost")) return true;
        else return false;
    }

}

1
2
3
4
5
6
7
8
9
10
    /// <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");
        }
    }

这是一种灵活的方法,可适应您从哪里进行编译以及是否关心所处的模式。

1
2
3
4
5
6
7
8
9
string testString1 ="\\\\bin\\\";
//string testString ="\\\\bin\\\\Debug\\\";
//string testString ="\\\\bin\\\
elease\\\";

if (AppDomain.CurrentDomain.BaseDirectory.Contains(testString))
{
    //Your code here
}


推荐阅读