从控件的构造函数中检测设计模式


99

这个问题开始,是否有可能从对象的构造函数中检测一个对象处于设计模式还是运行时模式?

我意识到这可能是不可能的,我将不得不更改我想要的内容,但是现在我对这个特定的问题感兴趣。

Answers:


192

您可以在名称空间中使用LicenceUsageMode枚举System.ComponentModel

bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);

2
优雅的解决方案,它比C#功能更好ISite.DesignMode
2014年

10
@Filip Kunc:如果这在OnPaint中不起作用,则可以在构造函数中检查此条件,并将其存储在类字段中。
IMil 2016年

3
在用户控件中覆盖WndProc时,这也不起作用。必须使用@IMil建议
Matt Skeldon

1
将它放在构造中是IMil的一个好主意,它为我工作。.我试图将它放在静态类字段中,但是(我认为)静态类字段在您首次调用它们时初始化,所以不是一个安全的解决方案。
Ibrahim Ozdemir '02

22

您是否正在寻找这样的东西:

public static bool IsInDesignMode()
{
    if (Application.ExecutablePath.IndexOf("devenv.exe", StringComparison.OrdinalIgnoreCase) > -1)
    {
        return true;
    }
    return false;
}

您也可以通过检查进程名称来做到这一点:

if (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv")
   return true;

4
适用于OnPaint,派生类,构造函数等。最佳解决方案。
Filip Kunc

14
恕我直言,这看起来像一个丑陋的解决方案。
卡米洛·马丁

5
注意此处可能发生内存泄漏。必须处理过程。
2013年

7
尽管我确信这在大多数用例中都可以正常工作,但是该解决方案有一个主要缺陷:(至少从理论上来说)Visual Studio不是唯一的设计者主机。因此,仅当您的设计器由称为的应用程序托管时,此解决方案才有效devenv
stakx-不再提供

2
与VS2013兼容,不同于当前接受的答案。
Moby Disk

9

组件...据我所知没有DesignMode属性。此属性由Control提供。但是问题是,当CustomControl位于设计器的窗体中时,该CustomControl在运行时模式下运行。

我已经体验到DesignMode属性仅在Form中有效。


谢谢你的提示!我以前从未意识到这一点,但是这很有意义。在这些情况下,将控件嵌入到另一个控件/表单中,使用adrianbanks提供的LicenseManager方法非常有效。每个+1!
乔什(Josh Stribling),

1
+1您绝对正确,这也是我的经验。当您将用户控件放在窗体上时,如果有任何鼠标输入或加载事件,则DesignMode仍会显示为false,因为您不在此控件的设计模式下。以我的经验,它会导致Visual Studio严重崩溃。
Kyle B

8

控件(窗体,用户控件等)继承Component classbool property DesignMode

if(DesignMode)
{
  //If in design mode
}

4
构造函数运行时未设置,也就是OP的初始发行版。可以使用它的第一刻OnHandleCreated

8

重要

使用Windows 窗体WPF有区别!

他们有不同的设计师,需要不同的检查。另外,当您混合使用Forms和WPF控件时,这很棘手。(例如,“窗体”窗口内的WPF控件)

如果只有Windows 窗体,请使用以下命令:

Boolean isInWpfDesignerMode   = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);

如果只有WPF,请使用此检查:

Boolean isInFormsDesignerMode = (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv");

如果您混合使用 Forms和WPF,请使用如下检查:

Boolean isInWpfDesignerMode   = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
Boolean isInFormsDesignerMode = (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv");

if (isInWpfDesignerMode || isInFormsDesignerMode)
{
    // is in any designer mode
}
else
{
    // not in designer mode
}

要查看当前模式,可以显示一个MessageBox进行调试:

// show current mode
MessageBox.Show(String.Format("DESIGNER CHECK:  WPF = {0}   Forms = {1}", isInWpfDesignerMode, isInFormsDesignerMode));

备注:

您需要添加名称空间System.ComponentModelSystem.Diagnostics


我认为您的命名具有误导性。当使用的WinForms命名为“isInWpfDesignerMode”和WPF它的“isInFormsDesignerMode”
中号Stoerzel

5

您应该使用Component.DesignMode属性。据我所知,不应从构造函数中使用它。


7
当您的控件在另一个控件或正在设计的窗体中时,这将不起作用。
埃里克

1
实际上,它在我的组件中效果很好。我总是必须添加if (!DesignMode)OnPaint方法以确保它不会浪费设计时间。
Bitterblue

4

该博客上介绍了另一种有趣的方法:http//www.undermyhat.org/blog/2009/07/in-depth-a-definitive-guide-to-net-user-controls-usage-mode-designmode-or -用户模式/

基本上,它测试从入口程序集中静态引用的执行程序集。它避免了跟踪程序集名称(“ devenv.exe”,“ monodevelop.exe” ..)的需要。

但是,它不适用于动态加载程序集的所有其他方案(VSTO是一个示例)。


链接已(有效)断开。现在,它重定向到最新的博客文章(当前为2016-03)。
Peter Mortensen

3

在设计人员的协助下...可以在所有地方的控件,组件中使用

    private bool getDesignMode()
    {
        IDesignerHost host;
        if (Site != null)
        {
            host = Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (host != null)
            {
                if (host.RootComponent.Site.DesignMode) MessageBox.Show("Design Mode");
                else MessageBox.Show("Runtime Mode");
                return host.RootComponent.Site.DesignMode;
            }
        }
        MessageBox.Show("Runtime Mode");
        return false;
    }

MessageBox.Show(线应删除。这只是让我确定它可以正常工作。



1

这是我在项目中使用的方法:

//use a Property or Field for keeping the info to avoid runtime computation
public static bool NotInDesignMode { get; } = IsNotInDesignMode();
private static bool IsNotInDesignMode()
{
    /*
    File.WriteAllLines(@"D:\1.log", new[]
    {
        LicenseManager.UsageMode.ToString(), //not always reliable, e.g. WPF app in Blend this will return RunTime
        Process.GetCurrentProcess().ProcessName, //filename without extension
        Process.GetCurrentProcess().MainModule.FileName, //full path
        Process.GetCurrentProcess().MainModule.ModuleName, //filename
        Assembly.GetEntryAssembly()?.Location, //null for WinForms app in VS IDE
        Assembly.GetEntryAssembly()?.ToString(), //null for WinForms app in VS IDE
        Assembly.GetExecutingAssembly().Location, //always return your project's output assembly info
        Assembly.GetExecutingAssembly().ToString(), //always return your project's output assembly info
    });
    //*/

    //LicenseManager.UsageMode will return RunTime if LicenseManager.context is not present.
    //So you can not return true by judging it's value is RunTime.
    if (LicenseUsageMode.Designtime == LicenseManager.UsageMode) return false;
    var procName = Process.GetCurrentProcess().ProcessName.ToLower();
    return "devenv" != procName //WinForms app in VS IDE
        && "xdesproc" != procName //WPF app in VS IDE/Blend
        && "blend" != procName //WinForms app in Blend
        //other IDE's process name if you detected by log from above
        ;
}

注意!!!:代码返回布尔表示是以设计模式!


1
    private void CtrlSearcher_Load(object sender, EventArgs e)
    {
           if(!this.DesignMode) InitCombos();
    }

尽管此代码可以回答问题,但提供有关如何和/或为什么解决问题的其他上下文将提高​​答案的长期价值。
Tiago Martins Peres李大仁

0

LicenseManager解决方案在OnPaint内不起作用,this.DesignMode也不起作用。我求助于与@Jarek相同的解决方案。

这是缓存的版本:

    private static bool? isDesignMode;
    private static bool IsDesignMode()
    {
        if (isDesignMode == null)
            isDesignMode = (Process.GetCurrentProcess().ProcessName.ToLower().Contains("devenv"));

        return isDesignMode.Value;
    }

请注意,如果您使用任何第三方IDE,或者Microsoft(或您的最终用户)决定将VS可执行文件的名称更改为'devenv'以外的名称,则此操作将失败。故障率将非常低,只需确保您处理可能导致代码失败的任何结果错误,就可以了。


0

如果要在运行时运行某些行而不是在Visual Studio设计器中运行,则应实现DesignMode属性,如下所示:

// this code is in the Load of my UserControl
if (this.DesignMode == false)
{
    // This will only run in run time, not in the designer.
    this.getUserTypes();
    this.getWarehouses();
    this.getCompanies();
}

0

使用自定义/用户控件时,默认情况下启用的计时器可能会导致崩溃。默认情况下禁用它们,仅在设计模式检查后启用

   public chartAdapter()
    {
        try
        {

            //Initialize components come here
            InitializeComponent();

            //Design mode check
            bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
            if (designMode)
                return;

            //Enable timers ONLY after designmode check, or else crash
            timerAutoConnect.Enabled = timerDraw.Enabled = true;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.