关于.net:带有嵌套控件的DesignMode

DesignMode with nested Controls

在开发控件时,有没有人找到针对DesignMode问题的有用解决方案?

问题在于,如果嵌套控件,则DesignMode仅适用于第一级。较低的第二级DesignMode将始终返回FALSE。

标准的技巧是查看正在运行的进程的名称,如果它是" DevEnv.EXE",那么它必须是studio,因此DesignMode确实为TRUE。

问题在于寻找ProcessName会在注册表和其他奇怪的地方工作,最终结果是用户可能没有查看进程名称所需的权限。此外,这条奇怪的路线非常慢。因此,我们不得不堆积更多的骇客才能使用单例,并且如果在询问进程名称时抛出错误,则假定DesignMode为FALSE。

一种确定DesignMode的好方法是按顺序进行的。最终让Microsoft将其内部修复到框架中会更好!


回顾这个问题,我现在"发现"了5种不同的方法,如下所示:

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
System.ComponentModel.DesignMode property

System.ComponentModel.LicenseManager.UsageMode property

private string ServiceString()
{
    if (GetService(typeof(System.ComponentModel.Design.IDesignerHost)) != null)
        return"Present";
    else
        return"Not present";
}

public bool IsDesignerHosted
{
    get
    {
        Control ctrl = this;

        while(ctrl != null)
        {
            if((ctrl.Site != null) && ctrl.Site.DesignMode)
                return true;
            ctrl = ctrl.Parent;
        }
        return false;
    }
}
public static bool IsInDesignMode()
{
    return System.Reflection.Assembly.GetExecutingAssembly()
         .Location.Contains("VisualStudio"))
}

为了尝试摆脱提出的三个解决方案,我创建了一个小测试解决方案-包含三个项目:

  • TestApp(winforms应用程序),
  • 子控件(dll)
  • SubSubControl(dll)

然后将SubSubControl嵌入到SubControl中,然后将其中一个嵌入到TestApp.Form中。

此屏幕截图显示了运行时的结果。
Screenshot

此屏幕快照显示了在Visual Studio中打开表单的结果:

Screenshot


在此页面上:

([Edit 2013]编辑,可使用@hopla提供的方法在构造函数中使用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/// <summary>
/// The DesignMode property does not correctly tell you if
/// you are in design mode.  IsDesignerHosted is a corrected
/// version of that property.
/// (see https://connect.microsoft.com/VisualStudio/feedback/details/553305
/// and http://stackoverflow.com/a/2693338/238419 )
/// </summary>
public bool IsDesignerHosted
{
    get
    {
        if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
            return true;

        Control ctrl = this;
        while (ctrl != null)
        {
            if ((ctrl.Site != null) && ctrl.Site.DesignMode)
                return true;
            ctrl = ctrl.Parent;
        }
        return false;
    }
}

我已经向Microsoft提交了错误报告;我怀疑它是否会随处可见,但无论如何都要投票,因为这显然是一个错误(无论它是否是"有意设计的")。


为什么不检查LicenseManager.UsageMode。
此属性的值可以为LicenseUsageMode.Runtime或LicenseUsageMode.Designtime。

是否要让代码仅在运行时中运行,请使用以下代码:

1
2
3
4
if (LicenseManager.UsageMode == LicenseUsageMode.Runtime)
{
  bla bla bla...
}

这是我在表格中使用的方法:

1
2
3
4
5
6
7
8
9
10
    /// <summary>
    /// Gets a value indicating whether this instance is in design mode.
    /// </summary>
    /// <value>
    ///     <c>true</c> if this instance is in design mode; otherwise, <c>false</c>.
    /// </value>
    protected bool IsDesignMode
    {
        get { return DesignMode || LicenseManager.UsageMode == LicenseUsageMode.Designtime; }
    }

这样,即使DesignMode或LicenseManager属性中的任何一个失败,结果也将是正确的。


我使用LicenseManager方法,但是从构造函数中缓存该值,以在实例的整个生命周期中使用。

1
2
3
4
5
6
7
8
public MyUserControl()
{
    InitializeComponent();
    m_IsInDesignMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
}

private bool m_IsInDesignMode = true;
public bool IsInDesignMode { get { return m_IsInDesignMode; } }

VB版本:

1
2
3
4
5
6
7
8
9
10
11
12
Sub New()
    InitializeComponent()

    m_IsInDesignMode = (LicenseManager.UsageMode = LicenseUsageMode.Designtime)
End Sub

Private ReadOnly m_IsInDesignMode As Boolean = True
Public ReadOnly Property IsInDesignMode As Boolean
    Get
        Return m_IsInDesignMode
    End Get
End Property

我的建议是对@ blueraja-danny-pflughoeft回复的优化。
此解决方案并非每次都计算结果,而只是在第一次时(对象无法将UsageMode从设计更改为运行时)

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
33
34
35
36
37
private bool? m_IsDesignerHosted = null; //contains information about design mode state
/// <summary>
/// The DesignMode property does not correctly tell you if
/// you are in design mode.  IsDesignerHosted is a corrected
/// version of that property.
/// (see https://connect.microsoft.com/VisualStudio/feedback/details/553305
/// and https://stackoverflow.com/a/2693338/238419 )
/// </summary>
[Browsable(false)]
public bool IsDesignerHosted
{
    get
    {
        if (m_IsDesignerHosted.HasValue)
            return m_IsDesignerHosted.Value;
        else
        {
            if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
            {
                m_IsDesignerHosted = true;
                return true;
            }
            Control ctrl = this;
            while (ctrl != null)
            {
                if ((ctrl.Site != null) && ctrl.Site.DesignMode)
                {
                    m_IsDesignerHosted = true;
                    return true;
                }
                ctrl = ctrl.Parent;
            }
            m_IsDesignerHosted = false;
            return false;
        }
    }
}


我们成功使用此代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static bool IsRealDesignerMode(this Control c)
{
  if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
    return true;
  else
  {
    Control ctrl = c;

    while (ctrl != null)
    {
      if (ctrl.Site != null && ctrl.Site.DesignMode)
        return true;
      ctrl = ctrl.Parent;
    }

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

由于所有方法都不可靠(DesignMode,LicenseManager)或高效(过程,递归检查),因此我在程序级别使用public static bool Runtime { get; private set }并将其显式设置在Main()方法内。


我自己从未对此感到迷惑,但是您难道不能只是从控件中返回父链,看看是否在您上方的任何位置设置了DesignMode?


我还没有意识到您无法调用Parent.DesignMode(而且我也已经在C#中学到了有关"受保护"的知识...)

这是一个反映性的版本:(我怀疑将designModeProperty设置为静态字段可能会带来性能上的优势)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static bool IsDesignMode(Control control)
{
    PropertyInfo designModeProperty = typeof(Component).
      GetProperty("DesignMode", BindingFlags.Instance | BindingFlags.NonPublic);

    while (designModeProperty != null && control != null)
    {
        if((bool)designModeProperty.GetValue(control, null))
        {
            return true;
        }
        control = control.Parent;
    }
    return false;
}

DesignMode是一个私有属性(据我所知)。答案是提供一个公开DesignMode属性的公共属性。然后,您可以级联备份用户控件链,直到遇到非用户控件或处于设计模式的控件为止。像这样....

1
2
3
4
5
6
7
8
9
  public bool RealDesignMode()
  {
     if (Parent is MyBaseUserControl)
     {
        return (DesignMode ? true : (MyBaseUserControl) Parent.RealDesignMode;
     }

     return DesignMode;
  }

您所有的UserControl都继承自MyBaseUserControl。或者,您可以实现一个暴露" RealDeisgnMode"的接口。

请注意,该代码不是实时代码,只是袖手旁观。 :)


最近我在使用嵌套的UserControls时必须在Visual Studio 2017中解决此问题。我结合了上面和其他地方提到的几种方法,然后对代码进行了调整,直到有了一个不错的扩展方法为止,该方法到目前为止可以接受。它执行一系列检查,并将结果存储在静态布尔变量中,因此每次检查最多只能在运行时执行一次。这个过程可能是过分的,但是却使代码无法在Studio中执行。希望这对某人有帮助。

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  public static class DesignTimeHelper
  {
    private static bool? _isAssemblyVisualStudio;
    private static bool? _isLicenseDesignTime;
    private static bool? _isProcessDevEnv;
    private static bool? _mIsDesignerHosted;

    /// <summary>
    ///   Property <see cref="Form.DesignMode"/> does not correctly report if a nested <see cref="UserControl"/>
    ///   is in design mode.  InDesignMode is a corrected that property which .
    ///   (see https://connect.microsoft.com/VisualStudio/feedback/details/553305
    ///   and https://stackoverflow.com/a/2693338/238419 )
    /// </summary>
    public static bool InDesignMode(
      this Control userControl,
      string source = null)
      => IsLicenseDesignTime
         || IsProcessDevEnv
         || IsExecutingAssemblyVisualStudio
         || IsDesignerHosted(userControl);

    private static bool IsExecutingAssemblyVisualStudio
      => _isAssemblyVisualStudio
         ?? (_isAssemblyVisualStudio = Assembly
           .GetExecutingAssembly()
           .Location.Contains(value:"VisualStudio"))
         .Value;

    private static bool IsLicenseDesignTime
      => _isLicenseDesignTime
         ?? (_isLicenseDesignTime = LicenseManager.UsageMode == LicenseUsageMode.Designtime)
         .Value;

    private static bool IsDesignerHosted(
      Control control)
    {
      if (_mIsDesignerHosted.HasValue)
        return _mIsDesignerHosted.Value;

      while (control != null)
      {
        if (control.Site?.DesignMode == true)
        {
          _mIsDesignerHosted = true;
          return true;
        }

        control = control.Parent;
      }

      _mIsDesignerHosted = false;
      return false;
    }

    private static bool IsProcessDevEnv
      => _isProcessDevEnv
         ?? (_isProcessDevEnv = Process.GetCurrentProcess()
                                  .ProcessName =="devenv")
         .Value;
  }

推荐阅读

    linux端口进程命令?

    linux端口进程命令?,系统,情况,地址,网络,信息,状态,灵活,工具,端口,命令,如

    linux进程的命令行?

    linux进程的命令行?,地址,工作,系统,信息,命令,管理,名称,进程,目录,服务,lin

    linux当前进程命令?

    linux当前进程命令?,系统,信息,工作,状态,命令,进程,情况,地址,软件,实时,lin

    linux下杀进程命令?

    linux下杀进程命令?,系统,管理,进程,命令,名称,代码,终端,结束,指令,信号,Lin

    linux关于的进程命令?

    linux关于的进程命令?,系统,进程,管理,命令,名称,代码,软件,信息,定期,状态,l

    linux向进程发送命令?

    linux向进程发送命令?,通信,地址,系统,时间,工作,信息,管理,状态,进程,数据,l

    linux重启进程号命令?

    linux重启进程号命令?,工作,系统,地址,标准,命令,设备,工具,信息,基础,情况,L

    linux中调度进程命令?

    linux中调度进程命令?,系统,状态,策略,实时,信息,进程,数据,管理,时间,异常,L

    linux检测进程命令?

    linux检测进程命令?,系统,服务,地址,状态,信息,检测,进程,命令,第一,软件,lin

    linux进程中断命令行?

    linux进程中断命令行?,系统,软件,管理,进程,信息,名字,名称,平台,命令,结束,l

    linux进程有关命令?

    linux进程有关命令?,系统,状态,信息,时间,进程,命令,百分比,暂停,名称,定期,L

    linux进程管理命令?

    linux进程管理命令?,系统,管理,地址,工作,状态,进程,信息,时间,基础,命令,Lin

    linux命令进程占系统?

    linux命令进程占系统?,系统,情况,时间,实时,基础,进程,命令,分析,信息,衍生,L

    linux追踪进程命令?

    linux追踪进程命令?,系统,进程,情况,状态,命令,软件,信息,程序,终端,参数,哪

    终止进程的命令linux?

    终止进程的命令linux?,系统,名称,进程,软件,名字,信息,平台,代码,命令,方式,L

    查询进程命令linux?

    查询进程命令linux?,系统,进程,名称,情况,信息,命令,状态,软件,工具,第一,哪

    linux进程命令解释?

    linux进程命令解释?,系统,状态,基础,进程,信息,时间,命令,实时,软件,名称,Lin

    linux孤儿进程命令?

    linux孤儿进程命令?,系统,进程,工具,状态,管理系统,管理,通信,百度,工作,命

    linux杀所有进程命令?

    linux杀所有进程命令?,系统,电脑,进程,状态,工具,通信,信息,材料,命令,终端,l

    linux命令行中断进程?

    linux命令行中断进程?,系统,管理,软件,进程,数字,名称,状态,命令,结束,方法,