91

有没有人在开发控件时找到了设计模式问题的有用解决方案?

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

标准的破解方法是查看正在运行的进程的名称,如果它是“DevEnv.EXE”,那么它必须是工作室,因此 DesignMode 真的是 TRUE。

问题在于寻找 ProcessName 通过注册表和其他奇怪的部分来解决,最终结果是用户可能没有查看进程名称所需的权限。另外这条奇怪的路线很慢。所以我们不得不增加额外的技巧来使用单例,如果在询问进程名称时抛出错误,则假设 DesignMode 为 FALSE。

确定 DesignMode 的一个很好的干净方法是有序的。真正让微软在框架内部修复它会更好!

4

13 回答 13

84

重新审视这个问题,我现在“发现”了 5 种不同的方法,如下所示:

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)
  • 子子控件 (dll)

然后我将 SubSubControl 嵌入到 SubControl 中,然后将每个嵌入到 TestApp.Form 中。

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

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

不运行截图

结论:似乎没有反射,构造函数中唯一可靠的是 LicenseUsage,而在构造函数之外唯一可靠的是“IsDesignedHosted”(由下面的BlueRaja 提供

PS:请参阅下面 ToolmakerSteve 的评论(我尚未测试):“请注意,IsDesignerHosted答案已更新为包含 LicenseUsage ...,因此现在测试可以简单地是 if (IsDesignerHosted)。另一种方法是在构造函数中测试LicenseManager并缓存结果。”

于 2009-04-02T07:02:22.477 回答
36

这个页面

[编辑 2013]编辑为在构造函数中工作,使用@hopla 提供的方法)

/// <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提交了错误报告;我怀疑它会去任何地方,但无论如何都要投票,因为这显然是一个错误(无论它是否是“设计”)。

于 2010-04-22T18:19:19.783 回答
29

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

您是否希望代码仅在运行时运行,请使用以下代码:

if (LicenseManager.UsageMode == LicenseUsageMode.Runtime)
{
  bla bla bla...
}
于 2008-12-06T21:29:10.010 回答
7

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

    /// <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 属性失败,结果也会正确。

于 2010-09-29T14:46:37.217 回答
6

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

public MyUserControl()
{
    InitializeComponent();
    m_IsInDesignMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
}

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

VB版:

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
于 2010-05-17T13:08:10.143 回答
3

由于没有一种方法是可靠的(DesignMode、LicenseManager)或有效的(过程、递归检查),我public static bool Runtime { get; private set }在程序级别使用 a 并在 Main() 方法中显式设置它。

于 2011-09-02T09:58:23.550 回答
3

我们成功地使用了这段代码:

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";
  }
}
于 2012-09-21T07:56:55.067 回答
3

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

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;
        }
    }
}
于 2016-01-27T15:37:12.203 回答
2

我自己从来没有被这个抓住过,但是你不能从控件回到父链,看看是否在你上方的任何地方设置了 DesignMode 吗?

于 2008-08-29T16:47:03.593 回答
1

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

  public bool RealDesignMode()
  {
     if (Parent is MyBaseUserControl)
     {
        return (DesignMode ? true : (MyBaseUserControl) Parent.RealDesignMode;
     }

     return DesignMode;
  }

您的所有用户控件都从 MyBaseUserControl 继承。或者,您可以实现一个公开“RealDeisgnMode”的接口。

请注意,此代码不是实时代码,只是即兴思考。:)

于 2008-08-29T16:59:22.063 回答
1

我没有意识到你不能调用 Parent.DesignMode (我也学到了一些关于 C# 中的“受保护”的东西......)

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

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;
}
于 2008-08-29T17:43:57.027 回答
0

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

  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;
  }
于 2019-01-17T19:37:55.233 回答
0

我在 .NET 5 中使用以下方法解决了这个问题:

public static bool InDesignMode()
{   
    return Process.GetCurrentProcess().ProcessName.Contains("DesignToolsServer");
}
于 2022-01-18T19:12:33.677 回答