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

时间:2009-07-22 15:45:22

标签: c# winforms

this question跟随,是否可以从对象的构造函数中检测一个是处于设计模式还是运行时模式?

我意识到这可能是不可能的,而且我必须改变我想要的东西,但是现在我对这个具体问题感兴趣。

17 个答案:

答案 0 :(得分:170)

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

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

答案 1 :(得分: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;

答案 2 :(得分:9)

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

我遇到过DesignMode属性仅在Form中正常工作。

答案 3 :(得分: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.ComponentModel System.Diagnostics

答案 4 :(得分:6)

控件(表单,用户控件等)继承具有Component class的{​​{1}}所以:

bool property DesignMode

答案 5 :(得分:5)

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

答案 6 :(得分:4)

该博客描述了另一种有趣的方法:http://www.undermyhat.org/blog/2009/07/in-depth-a-definitive-guide-to-net-user-controls-usage-mode-designmode-or-usermode/

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

但是,它在动态加载程序集的所有其他方案中都不起作用(VSTO就是一个例子)。

答案 7 :(得分:2)

与设计师合作......它可以在各个地方的控制,组件中使用

    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(行。它只能让我确信它能正常工作。

答案 8 :(得分: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
        ;
}

注意!!! :在设计模式下,返回的bool代码指示

答案 9 :(得分:1)

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

答案 10 :(得分:1)

像许多其他人一样,我在设计 Windows 窗体用户控件时已经多次遇到这个问题。
但是今天,我遇到了一种情况,上面提到的解决方案都不适合我。
问题是,LicenseManager.UsageMode 仅在构造函数中可靠地工作,而 DesignMode 仅在构造函数之外工作,并不总是如此。这是我的经验,这就是is said in a discussion on GitHub
另一个问题是继承,以及将用户控件嵌入另一个用户控件中的另一个用户控件中。 最迟在嵌入用户控件的第 2 级,两种方式都失败了!

这可以显示在我为此测试创建的 UserControls 中。每个 UC 有 3 个标签:

  1. 它的 (project name)type name

  2. 价值

    • DesignMode (true: "DM=1"),
    • LicenseManager.UsageMode == LicenseUsageMode.Designtime,本地查询,(true: "local_LM-DT=1")
    • LicenseManager.UsageMode == LicenseUsageMode.Designtime,从构造函数中写入的私有字段查询 (true: "ctor_LM-DT=1")

    在构造函数(“CTOR”)和从构造函数(“CFCtor”)调用的方法中获取所有内容

  3. 与2)相同的值
    全部在 Load 事件(“Load()”)和从 Load 事件(“CFLoad”)调用的方法内进行

我创建的用户控件和表单是(在 WinForms 设计器中显示的所有屏幕截图):

  • UserControl1

    • 包含 3 个标签

    enter image description here
    Designer 不执行构造函数或事件,因此未填充标签。

  • UserControl1a

    • 继承自 UserControl1
    • 包含另外 2 个标签

    enter image description here
    Designer 执行父 UserControl 的构造函数和事件。

  • UserControl2:包含

    • 包含 3 个标签
    • 包含 1 UserControl1
    • 包含 1 UserControl1a

    enter image description here
    设计器执行嵌入的 UserControls 的构造函数和事件。
    只有 1 级嵌入。

  • UserControl3

    • 包含 3 个标签
    • 包含 1 UserControl2

    enter image description here
    设计器执行嵌入的 UserControls 的构造函数和事件。
    2级嵌入:2级嵌入的UserControl里面的值是错误的。

  • Form1

    • 包含 3 个标签
    • 包含 1 UserControl1
    • 包含 1 UserControl1a
    • 包含 1 UserControl2
    • 包含 1 个 UserControl3

    enter image description here 设计器执行嵌入的 UserControls 的构造函数和事件。
    3级嵌入:UserControl中2级和3级嵌入值错误。

从截图中可以看出,“ctor_LM-DT”始终为 1。
这意味着,必须将 LicenseManager 的值存储在成员字段中才能获得 Designer 使用的有效状态:

private LicenseUsageMode m_ctorLMUsageMode = LicenseManager.UsageMode;

为了完整起见,这里是我的一些可用于重现测试的代码:

public static string CreateText(bool i_isInDesignMode, LicenseUsageMode i_localLicenseUsageMode, LicenseUsageMode i_ctorLicenseUsageMode)
{
  return $"DM={(i_isInDesignMode ? 1 : 0)} local_LM-DT={(i_localLicenseUsageMode == LicenseUsageMode.Designtime ? 1 : 0)} ctor_LM-DT={(i_ctorLicenseUsageMode == LicenseUsageMode.Designtime ? 1 : 0)}";
}

其他 UserControl 相同或相似:

public partial class UserControl1 : UserControl
{
  private LicenseUsageMode m_ctorLMUsageMode = LicenseManager.UsageMode;

  public UserControl1()
  {
    InitializeComponent();

    label2.Text = $"CTOR: {CInitTester.CreateText (DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
    CalledFromCtor();
  }

  private void UserControl1_Load(object sender, EventArgs e)
  {
    label3.Text = $"Load(): {CInitTester.CreateText(DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
    CalledFromLoad();
  }

  private void CalledFromCtor()
  {
    label2.Text += $"\r\nCFCtor: {CInitTester.CreateText (DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
  }

  private void CalledFromLoad()
  {
    label3.Text += $"\r\nCFLoad: {CInitTester.CreateText (DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
  }
}

答案 11 :(得分:1)

是的,您可以从对象的构造函数中检查您是否处于“设计模式”。但是使用 WinForms DesignMode 属性并不总是按预期工作。另一种选择:

这是我使用 Visual Studio 在 C# 中检查 DesignMode 的技术,它确实适用于构造函数。

// add this class...
public static class Globals
{
    static Globals() => DesignMode = true;
    public static bool DesignMode { get; set; }
}

// and modify your existing class...
public static class Program
{
    public static void Main()
    {
        Globals.DesignMode = false;
        // ...
        // ... and then the rest of your program
        //
        //  in any of your code you can check Globals.DesignMode for
        //  the information you want.
    }
}

此解决方案轻量级且简单。缺点是您必须记住清除主代码中的标志。

在检查“设计模式”时,我们实际上是在检查我们的代码是否正在执行,因为我们的整个程序正在运行,或者我们的部分代码正在由 VS 设计器执行。使用此解决方案,该标志仅在整个程序运行时设置为 false。

答案 12 :(得分: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”以外的其他名称,则会失败。失败率将非常低,只需确保您处理因此而导致失败的代码中可能出现的任何错误,您就可以了。

答案 13 :(得分:0)

如果要在运行时运行某些行但不在Visual Studio设计器中运行,则应按如下方式实现DesignMode属性:

scala>spark.sql("select trunc(id),trunc(time_stamp),trunc(time_stamp,name)  
from sample_table").collect.foreach(println)

答案 14 :(得分:0)

您可以使用

if (DesignerProperties.GetIsInDesignMode(this))
{
...
}

答案 15 :(得分: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;

答案 16 :(得分:0)

在 .NET Core 3.1 上创建 WinForms 应用程序时,我无法在 Visual Studio 2019 中使用任何这些解决方案。

Appllication.ProcessNameProcess.ProcessName 都为我返回 "DesignToolsServer",当控件位于另一个控件中或仅位于表单本身时,LicenseManager.UsageMode 返回 LicenseUsageMode.Runtime

我确实使用 Application.ProcessName == "DesignToolsServer" 让它工作了。