【发布时间】:2010-11-13 01:36:00
【问题描述】:
继this question 之后,是否有可能从对象的构造函数中检测一个是处于设计模式还是运行时模式?
我意识到这可能是不可能的,我必须改变我想要的,但现在我对这个具体问题很感兴趣。
【问题讨论】:
继this question 之后,是否有可能从对象的构造函数中检测一个是处于设计模式还是运行时模式?
我意识到这可能是不可能的,我必须改变我想要的,但现在我对这个具体问题很感兴趣。
【问题讨论】:
您可以在System.ComponentModel 命名空间中使用LicenceUsageMode 枚举:
bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
【讨论】:
ISite.DesignMode。
LicenseManager.UsageMode 在 UserControl A 中使用,并且此 UC A 在另一个 UserControl 或另一个 Assembly 中的 Form B 中使用,这将不起作用。在这种情况下,我仍然得到Runtime 而不是DesignTime。
你在寻找这样的东西吗:
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;
【讨论】:
devenv 的应用程序托管时,此解决方案才有效。
Component ...据我所知没有 DesignMode 属性。此属性由 Control 提供。但是问题是当CustomControl位于设计器中的一个Form中时,这个CustomControl是在运行时模式下运行的。
我体验过 DesignMode 属性只在 Form 中正确工作。
【讨论】:
控件(表单、用户控件等)继承 Component class,它具有 bool property DesignMode 所以:
if(DesignMode)
{
//If in design mode
}
【讨论】:
OnHandleCreated。
重要
使用 Windows Forms 或 WPF 是有区别的!!
他们有不同的设计师,需要不同的检查。 此外,当您混合 Forms 和 WPF 控件时,这很棘手。 (例如,窗体窗口内的 WPF 控件)
如果您有 Windows 仅表单,请使用:
Boolean isInWpfDesignerMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
如果您有 仅 WPF,请使用此检查:
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));
备注:
您需要添加命名空间 System.ComponentModel 和 System.Diagnostics。
【讨论】:
您应该使用 Component.DesignMode 属性。据我所知,这不应该在构造函数中使用。
【讨论】:
if (!DesignMode) 添加到 OnPaint 方法中,以确保它不会在设计时产生垃圾邮件。
你可以用这个
if (DesignerProperties.GetIsInDesignMode(this))
{
...
}
【讨论】:
在那个博客上描述了另一种有趣的方法: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 就是一个例子)。
【讨论】:
在设计者的配合下……可以在Controls、Components等各个地方使用
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( 行应该被删除。它只会让我确保它正常工作。
【讨论】:
像许多其他人一样,我在设计 Windows 窗体用户控件时已经多次遇到过这个问题。
但是今天,我遇到了一种情况,上面提到的解决方案都不适合我。
问题是,LicenseManager.UsageMode 只能在构造函数中可靠地工作,而 DesignMode 只能在构造函数之外工作,而且并非总是如此。这是我的经验,这就是is said in a discussion on GitHub。
另一个问题来自于继承,以及将用户控件嵌入到另一个用户控件中的另一个用户控件中。 最迟在第 2 级嵌入用户控件时,两种方式都失败了!
这可以显示在我为此测试创建的用户控件中。每个 UC 都有 3 个标签:
它的(project name) 和type name
价值观
DesignMode (true: "DM=1"),LicenseManager.UsageMode == LicenseUsageMode.Designtime,本地查询,(true: "local_LM-DT=1")LicenseManager.UsageMode == LicenseUsageMode.Designtime,从构造函数中写入的私有字段查询 (true: "ctor_LM-DT=1")全部在构造函数(“CTOR”)和从构造函数(“CFctor”)调用的方法中获取
与 2) 中的值相同
全部在Load 事件(“Load()”)和从Load 事件(“CFLoad”)调用的方法中获取
我创建的用户控件和表单是(所有屏幕截图都显示在 WinForms 设计器中):
UserControl1:
UserControl1a:
UserControl1
UserControl2:包含
UserControl1
UserControl1a
UserControl3:
UserControl2
Form1:
UserControl1
UserControl1a
UserControl2
UserControl3。
设计器执行嵌入式用户控件的构造函数和事件。
3 级嵌入:在第 2 和第 3 嵌入级别的 UserControl 内的值是错误的。
从截图中可以看出,“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)}";
}
}
【讨论】:
这是我在项目中使用的方法:
//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代码表示NOT处于设计模式!
【讨论】:
在 .NET Core 3.1 上创建 WinForms 应用程序时,我无法在 Visual Studio 2019 中使用任何这些解决方案。
Appllication.ProcessName 和 Process.ProcessName 都为我返回 "DesignToolsServer",当控件位于另一个控件中或仅在表单本身上时,LicenseManager.UsageMode 返回 LicenseUsageMode.Runtime。
我确实使用Application.ProcessName == "DesignToolsServer" 让它工作。
【讨论】:
是的,您可以从对象的构造函数中检查您是否处于“设计模式”。但使用 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.
}
}
此解决方案轻巧且简单。缺点是您必须记住清除 Main 代码中的标志。
在检查“设计模式”时,我们实际上是在检查我们的代码是否正在执行,因为我们的整个程序正在运行,还是因为我们的部分代码正在由 VS 设计器执行。使用此解决方案,该标志仅在整个程序运行时设置为 false。
【讨论】:
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”以外的名称,这将失败。失败率会非常低,只要确保你处理了代码中可能出现的任何由此导致的错误,你会没事的。
【讨论】:
如果你想在运行时而不是在 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();
}
【讨论】:
private void CtrlSearcher_Load(object sender, EventArgs e)
{
if(!this.DesignMode) InitCombos();
}
【讨论】:
默认启用的计时器在使用自定义/用户控件时可能会导致崩溃。默认禁用,只有在设计模式检查后才启用
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;
【讨论】: