ActionList / Smart Tag面板上的自定义UITypeEditor

时间:2011-08-25 19:53:19

标签: .net windows-forms-designer design-time uitypeeditor actionlist

我有一个自定义UserControl,其属性名为ParentNode,属于OptionsNode,它继承了TreeNode。我的控件包含一个TreeView,其中许多节点在设计时显示。 ParentNode属性应该允许用户选择TreeView中的一个节点,类似于如何从属性网格中的下拉列表中选择组件,然后下拉列表显示所有可用组件。例如,任何表单的AcceptButton属性都会显示一个下拉列表,其中包含表单上的所有按钮以供选择。

为了在属性网格中获得此行为,我为OptionsNode类编写了一个自定义UITypeEditor。这告诉属性网格显示一个下拉列表,在这个下拉列表中我添加了一个ListBox,其中填充了TreeView中所有节点的列表。这很好用,用户可以通过单击它来下拉“属性”并选择一个节点。

现在,在做了一些工作后,我实现了一个自定义ControlDesigner,以及一个ActionList,有时也称为智能标记面板。我说的是当您单击某些控件右上角的[>]按钮时弹出的常用属性/设计器方法的小弹出窗口(例如,TabControl允许您从那里添加/删除tabpages)。

我以前都做过这件事,而且工作正常。现在的问题是我想在ActionList面板上显示相同的ParentNode属性。因此,DesignerActionList类具有“代理属性”,它将属性值从ActionList传递到控件,反之亦然,完全如文档和本文所述:http://msdn.microsoft.com/en-us/magazine/cc163758.aspx#S3

代码:

Friend Class OptionsPanelActionList
    Inherits DesignerActionList

    Public Sub New(ByVal host As OptionsPanel)
        MyBase.New(host)
    End Sub

    Public Property ParentNode As OptionsNode
        Get
            Return Me.Host.ParentNode
        End Get
        Set(value As OptionsNode)                 
            Me.SetProperty("ParentNode", value)                 
            Me.DesignerActionService.Refresh(Me.Host)
        End Set
    End Property

    Public Overrides Function GetSortedActionItems() As DesignerActionItemCollection
        Dim items As New DesignerActionItemCollection

        items.Add(New DesignerActionPropertyItem("ParentNode", "Parent node:", String.Empty, "Gets or sets the parent node."))

        Return items
    End Function

End Class

然而,这不起作用。 ActionList只是在智能标记面板中显示TextBox而不是我的自定义UITypeEditor。

我在之前链接的文章(http://msdn.microsoft.com/en-us/magazine/cc163758.aspx#S3)中阅读了更多内容,他特别针对这个问题。他的Clock控件有一个Face属性,带有FaceEditor UITypeEditor,允许人们通过下拉列表以图形方式选择一个钟面(数字,模拟或两者)。

他的解决方案是使用Editor属性简单地修饰代理属性,与原始Face属性相同。

好的,我试过了:

    <Editor(GetType(Editors.OptionsNodeEditor), GetType(UITypeEditor))> _
    Public Property ParentNode As OptionsNode
        Get
            Return Me.Host.ParentNode
        End Get
        Set(value As OptionsNode)                 
            Me.SetProperty("ParentNode", value)                 
            Me.DesignerActionService.Refresh(Me.Host)
        End Set
    End Property

当我打开动作列表窗口时,它会显示下拉样式而不是TextBox。大!但是当我尝试打开下拉列表时,我收到一个错误: “使用下拉列表时出错:无法将'OptionsPanelActionList'类型的对象强制转换为'OptionsPanel'”

我不明白这个错误。它似乎试图将OptionsPanelActionList对象强制转换为OptionsPanel。 OptionsPanel是我正在设计的控件(OptionsPanelActionList是OptionsPanelDesigner中的ActionList,是OptionsPanel控件的设计者),但我不知道它在这里是如何相关的。我不是在任何地方施展,但显然代码是在幕后的某个地方进行的。

我错过了什么?为什么我的编辑器在尝试使用自定义UITypeEditor时会抛出错误,而文章声明它应该有效?

谢谢!

1 个答案:

答案 0 :(得分:0)

我自己解决了。

问题确实是对OptionsPanel的强制转换。它出现在我的自定义UITypeEditor中。我需要对我正在编辑的控件(OptionsPanel)的引用,并发现我可以通过context.Instance属性获取它:

Public Overrides Function EditValue(context As System.ComponentModel.ITypeDescriptorContext, provider As System.IServiceProvider, value As Object) As Object
    Dim panel As OptionsPanel = DirectCast(context.Instance, OptionsPanel)
    '...
End Function

显然,通过ActionList / Smart Tag窗口编辑属性时,context.Instance对象不是面板,而是ActionList类的实例。所以我现在首先尝试将Instance转换为OptionsPanel,如果失败,我认为它是ActionList类并使用其Host(或Control)属性来获取OptionsPanel。

到目前为止似乎工作!