带嵌套控件的DesignMode

时间:2020-03-05 18:45:03  来源:igfitidea点击:

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

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

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

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

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

解决方案

回答

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

回答

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

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

     return DesignMode;
  }

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

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

回答

我还没有意识到我们不能调用Parent.DesignMode(而且我已经在Ctoo中了解到有关"受保护的"的知识...)

这是一个反射版本:(我怀疑将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;
}

回答

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

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

if (LicenseManager.UsageMode == LicenseUsageMode.Runtime)
{
  bla bla bla...
}

回答

再次讨论这个问题,我现在"发现"了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)
  • SubSubControl(dll)

然后,我将SubSubControl嵌入SubControl中,然后将其中之一嵌入TestApp.Form中。

此屏幕快照显示了运行时的结果。

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

结论:似乎没有经过反思,构造函数内唯一可靠的是LicenseUsage,而构造函数外唯一可靠的是'IsDesignedHosted'(由下面的BlueRaja提出)

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

回答

在此页面上:

([Edit 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提交了错误报告;我怀疑它是否会随处可见,但无论如何都应投票赞成,因为这显然是一个错误(无论是否"设计使然")。

回答

我使用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

回答

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

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