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

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

我意识到这可能是不可能的,我将不得不改变我想要的,但现在我对这个具体的问题感兴趣。

76270 次浏览

你在找这样的东西吗:

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;

You should use Component.DesignMode property. As far as I know, this shouldn't be used from a constructor.

可以在 System.ComponentModel命名空间中使用 许可证使用模式枚举:

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

与设计师合作... 它可以用于控件,组件,在所有的地方

    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(线应该被删除。它只是让我确信它正常工作。

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

我经历过 DesignMode 属性只能在 Form 中正确工作。

Another interesting method is described on that blog: 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 就是一个例子)。

控件(窗体、用户控件等)继承具有 bool property DesignModeComponent class,因此:

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

许可证管理器解决方案不能在 OnPaint 内部工作,这个.DesignMode 也不能。

Here's the cached version:

    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”以外的其他名称,那么这将失败。失败率将非常低,只要确保处理了由此导致的代码失败中可能出现的任何结果错误,就不会有问题。

很重要

使用 Windows表格WPF是有区别的! !

他们有不同的设计师和需要 different checks。 此外,当您混合使用 Forms 和 WPF 控件时,会遇到一些麻烦(例如,在 Forms 窗口中使用 WPF 控件)

如果你使用的是 Windows表格,请使用以下命令:

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

如果你有 WPF only,使用这个检查:

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

如果你有表单和 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));

备注:

您需要添加名称空间 系统组件模型系统,诊断

If you want to run some lines when it is running but not in the Visual Studio designer, you should implement the DesignMode property as follows:

// 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();
}

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

//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
;
}

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

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

你可以用这个

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

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

   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;

在 VisualStudio2019中创建 WinForms 应用程序时,我无法获得这些解决方案中的任何一个。NET Core 3.1.

Appllication.ProcessNameProcess.ProcessName都为我返回 "DesignToolsServer",当 Control 在另一个控件中或者仅仅在窗体本身上时,LicenseManager.UsageMode返回 LicenseUsageMode.Runtime

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

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

这可以在我为这个测试创建的用户控件中显示。每个 UC 有3个标签:

  1. 它的 (project name)type name

  2. 的价值观

    • DesignMode(true: "DM=1") ,
    • LicenseManager.UsageMode == LicenseUsageMode.Designtime,本地查询(true: “ local _ LM-DT = 1”)
    • 从构造函数中编写的私有字段(true: “ ctor _ LM-DT = 1”)查询 LicenseManager.UsageMode == LicenseUsageMode.Designtime

    都在构造函数(“ CTOR”)和从构造函数(“ CFCtor”)调用的方法中取得

  3. 与2中的值相同)
    都在 Load事件(“ Load ()”)和从 Load事件(“ CFLoad”)调用的方法中取得

我创建的 UserControls 和 Form 是(在 WinForms Designer 中显示的所有屏幕截图) :

  • 返回文章页面

    • 包含3个标签

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

  • UserControl1a:

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

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

  • 包含

    • contains 3 labels
    • contains 1 UserControl1
    • 含有1个 UserControl1a

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

  • 返回文章页面

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

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

  • 返回文章页面

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

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

从截图中可以看到,“ ctor _ LM-DT”总是1。
这意味着,要获得 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)}";
}

其他用户控件相同或相似:

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)}";
}
}

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

这是我使用 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.
}
}

这个解决方案是轻量级和简单的。缺点是您必须记住清除 Main 代码中的标志。

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