自定义控件集合 - 在设计时添加项目?

时间:2015-05-09 03:11:13

标签: vb.net

我正在尝试创建一个类似于Outlook风格的侧边栏的可重用控件。我有一个CustomPanel。我还有一个CustomCollectionControl,它继承自流布局面板。在设计时,我想通过属性窗口将(x)CustomPanel添加到我的CustomCollectionControl。

当我尝试从属性窗口中的(Collection)列表添加时,它将显示在列表中,但不会将其添加到表单上的控件。

到目前为止,这是我的代码。

Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms

Public Class CustomCollectionControl

    Inherits FlowLayoutPanel

    ''' <summary> 
    ''' Required designer variable.
    ''' </summary>
    Private _mComponents As Container = Nothing

    Private _mCustompanels As CustomPanelCollection

    Public Sub New()

        ' This call is required by the Windows.Forms Form Designer.
        InitializeComponent()

        SetStyle(ControlStyles.DoubleBuffer, True)
        SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        _mCustompanels = New CustomPanelCollection(Me)

        Padding = New Padding(0)

    End Sub

#Region "Component Designer generated code"
    ''' <summary> 
    ''' Required method for Designer support - do not modify 
    ''' the contents of this method with the code editor.
    ''' </summary>
    Private Sub InitializeComponent()
        _mComponents = New System.ComponentModel.Container()
    End Sub
#End Region

    <EditorBrowsable(EditorBrowsableState.Always)> _
    <Browsable(True)> _
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
    <Bindable(True)> _
    Public Property CustomPanels() As CustomPanelCollection
        Get
            Return _mCustompanels
        End Get
        Set(value As CustomPanelCollection)
            _mCustompanels = value
        End Set
    End Property

    Protected Overrides Sub OnResize(e As EventArgs)

        MyBase.OnResize(e)

    End Sub

End Class

Public Class CustomPanelCollection
    Inherits CollectionBase

    Private _mControl As CustomCollectionControl

    Private _mCustomCollectionControl As CustomCollectionControl

    Friend Sub New(control As CustomCollectionControl)

        _mCustomCollectionControl = control

    End Sub

    Default Public ReadOnly Property Item(index As Integer) As CustomPanel
        Get
            Return DirectCast(List(index), CustomPanel)
        End Get
    End Property

    Public Function Contains(cPanel As CustomPanel) As Boolean

        Return List.Contains(cPanel)

    End Function

    Public Function Add(cPanel As CustomPanel) As Integer

        Dim i As Integer

        i = List.Add(cPanel)
        cPanel.Control = _mCustomCollectionControl

        Return i

    End Function

    Public Sub Remove(cPanel As CustomPanel)

        List.Remove(cPanel)
        cPanel.Control = Nothing

    End Sub

End Class

Public Class CustomPanel
    Inherits Panel

    Friend Control As CustomCollectionControl

    Public Sub New()

        ' TODO Set Stuff!
        Height = 100
        BorderStyle = BorderStyle.FixedSingle
        Margin = New Padding(0)
        Padding = New Padding(0)

        Dim cBtn As New Button
        cBtn.Height = 30
        Controls.Add(cBtn)
        cBtn.Dock = DockStyle.Top

    End Sub

End Class

我需要找出在设计时通过属性窗口添加CustomPanel的时间,如何使用更改来更新控件?

2 个答案:

答案 0 :(得分:1)

基本问题是,为了使流布局逻辑适用于您的面板,它们需要位于基本控件的ControlCollection中。如果/当您通过属性IDE公开它时,标准集合编辑器允许将任何控件添加到它。

另一方面,您的CustomPanels()属性仅允许CustomPanel个控件,但它们存储在不同的集合中,因此它们不会显示在表单上。

如果添加SmartTag集合,CustomPanel仅添加Controls的操作是非常可行的解决方法。我不确定您希望它们能够编辑多少个标准Panel属性,并且由于无法指定子按钮属性,因此集合编辑器和{{之间似乎没有太大区别1}}。我认为这是因为它正在进行中和/或被删除以发布一个最小的例子。

另一种方法是摆脱额外的集合并使用自定义集合编辑器,它将控制类型限制为你想要的。如下所示。

注意:

  • 我更改了通用名称,以便于阅读。 SmartTag现在为CustomCollectionControlFlowLayoutPanelExCustomPanel
  • 你的按钮没有连接到任何东西,它们也没有暴露,所以我不确定你打算如何使用它们。
  • 由于FlowPanel所做的只是存储一个按钮,为什么不省略它,只添加一定大小的按钮?
  • 代码还有其他几个问题(例如FlowPanel应该实现CustomPanel/FlowPanel,因为它正在创建内容)。忽略这些和其他问题,以便专注于实现最小的自定义集合编辑器。

FlowLayoutPanelEx和FlowPanel:

IDisposable

您拥有它的方式,用户可以更改集合编辑器中的任何' collection editor will need this: Imports System.ComponentModel.Design Public Class FlowLayoutPanelEx Inherits FlowLayoutPanel Public Sub New() ' This call is required by the Windows.Forms Form Designer. ' {PL} - no, it is not 'InitializeComponent() SetStyle(ControlStyles.DoubleBuffer, True) SetStyle(ControlStyles.AllPaintingInWmPaint, True) Padding = New Padding(0) End Sub <EditorBrowsable(EditorBrowsableState.Always), Browsable(True), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Bindable(True), Editor(GetType(FlowPanelCollectionEditor), GetType(System.Drawing.Design.UITypeEditor))> Public Overloads Property Controls() As ControlCollection Get Return MyBase.Controls End Get Set(value As ControlCollection) End Set End Property End Class Public Class FlowPanel Inherits Panel ' ToDo: implememt IDisposable Private myBtn As Button ' allow user to specify the text for the child button Public Property ButtonText As String Get If myBtn IsNot Nothing Then Return myBtn.Text Else Return String.Empty End If End Get Set(value As String) myBtn.Text = value End Set End Property Public Sub New() ' TODO Set Stuff! Height = 100 BorderStyle = BorderStyle.FixedSingle Margin = New Padding(0) Padding = New Padding(0) Height = 40 myBtn = New Button myBtn.Height = 30 Controls.Add(myBtn) myBtn.Dock = DockStyle.Top End Sub End Class 属性,包括您明确设置的属性。我不知道你最终想要做什么来提供替代品,除了它似乎可能是面板是化妆品,也许只有一个按钮就足够了。

请注意FlowPanel属性上的其他Editor属性。这告诉VS使用该集合编辑器:

Controls

结果:

集合编辑器仅添加FlowPanels:

enter image description here

如您所见,可以从集合编辑器设置新的Public Class FlowPanelCollectionEditor Inherits CollectionEditor Public Sub New(t As Type) MyBase.New(t) End Sub ' *** Magic happens here: *** ' override the base class to SPECIFY the Type allowed ' rather than letting it derive the Types from the collection type ' which would allow any control to be added Protected Overrides Function CreateNewItemTypes() As Type() Dim ValidTypes As Type() = {GetType(FlowPanel)} Return ValidTypes End Function Public Overrides Function EditValue(context As ITypeDescriptorContext, provider As IServiceProvider, value As Object) As Object Return MyBase.EditValue(context, provider, value) End Function End Class 属性。将控件添加到Controls集合以在表单上使用时,按钮上会显示ButtonText

enter image description here enter image description here

请注意,用户仍然可以将ButtonText或其他内容拖到您的TextBox,然后它就会接受它。这是上面提到的另一个“其他问题”。

关于CodeProject, Enhanced CollectionEditor Framework的文章提供了对集合和自定义集合编辑器的相当全面的概述。

它包含一个自定义集合编辑器框架,但它不会按原样处理这种情况。如果您从FlowLayoutPanelEx方法中删除NotOverridable并重新编译,则应该能够从CreateNewItemTypes继承并使用它提供的一些其他功能。

实际上并不需要;如上面的代码所示,限制允许的类型并不多。当您修改EnhancedCollectionEditor并将按钮修改为最终形式时,该文章可能很有价值。 (免责声明:我写了这篇文章)。

答案 1 :(得分:0)

我在这里添加它是因为我不能在评论中这样做,因为文本和图像太多了。此外,也许有人从搜索引擎来到这里可以了解该怎么做。

这是我想通过控件实现的目标:

关闭 enter image description here

打开 enter image description here

这是编辑后的代码,允许单击(平面样式)按钮并打开父面板。这是一个非常粗略的方法,但是我把它放在一起检查它是否有效,然后我把它花了很多时间:

' collection editor will need this:
Imports System.ComponentModel.Design
Imports System.Windows.Forms
Imports System.ComponentModel
Imports System.Drawing

Public Class FlowLayoutPanelEx
    Inherits FlowLayoutPanel

    Public Sub New()

        SetStyle(ControlStyles.DoubleBuffer, True)
        SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        Padding = New Padding(0)
        BackColor = Color.FromKnownColor(KnownColor.ControlDark)
    End Sub

    <EditorBrowsable(EditorBrowsableState.Always),
    Browsable(True),
    DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
    Bindable(True),
    Editor(GetType(FlowPanelCollectionEditor),
           GetType(System.Drawing.Design.UITypeEditor))>
    Public Overloads Property Controls() As ControlCollection
        Get
            Return MyBase.Controls
        End Get
        Set(value As ControlCollection)

        End Set
    End Property

End Class

Public Class HeaderButton
    Inherits Button

    Public Property BtnID As Integer
    Public Property BtnColor As System.Drawing.Color
    Public Event ButtonClicked(sender As HeaderButton, buttonID As Int32)

    Private Sub clicked(sender As Object, e As EventArgs) Handles Me.Click
        RaiseEvent ButtonClicked(Me, BtnID)
    End Sub

End Class

Public Class FlowPanel
    Inherits Panel
    ' ToDo: implememt IDisposable

    Private myBtn As HeaderButton

    ' allow user to specify the text for the child button 
    Public Property ButtonText As String
        Get
            If myBtn IsNot Nothing Then
                Return myBtn.Text
            Else
                Return String.Empty
            End If
        End Get
        Set(value As String)
            myBtn.Text = value
        End Set
    End Property

    Public Sub New()

        BorderStyle = BorderStyle.FixedSingle
        Margin = New Padding(0)
        Padding = New Padding(0)
        Height = 32
        BackColor = Color.FromKnownColor(KnownColor.Info)
        myBtn = New HeaderButton
        AddHandler myBtn.ButtonClicked, AddressOf Me.ItemButtonClicked

        myBtn.Height = 30
        myBtn.Margin = New Padding(0)
        myBtn.Padding = New Padding(0)
        myBtn.Dock = DockStyle.Top
        myBtn.FlatStyle = FlatStyle.Flat
        BackColor = Color.FromKnownColor(KnownColor.Control)
        Controls.Add(myBtn)

    End Sub

    Public Sub ItemButtonClicked(ByVal btn As HeaderButton, ByVal buttonID As Int32)

        If btn.Parent.Height = 32 Then
            btn.Parent.Height = 200
        Else : btn.Parent.Height = 32
        End If

    End Sub

End Class

Public Class FlowPanelCollectionEditor
    Inherits CollectionEditor

    Public Sub New(t As Type)
        MyBase.New(t)
    End Sub

    ' *** Magic happens here: ***
    ' override the base class to SPECIFY the Type allowed
    ' rather than letting it derive the Types from the collection type
    ' which would allow any control to be added
    Protected Overrides Function CreateNewItemTypes() As Type()
        Dim ValidTypes As Type() = {GetType(FlowPanel)}
        Return ValidTypes

    End Function

    Public Overrides Function EditValue(context As ITypeDescriptorContext,
                                        provider As IServiceProvider,
                                        value As Object) As Object
        Return MyBase.EditValue(context, provider, value)
    End Function

End Class

我还有很多工作要做,比如在设计器中显示对控件的更改,实现Idisposable,在侧面添加可折叠按钮,并通过表单传递面板的高度值,以便打开全高。我可能会画出按钮来获得标准按钮无法提供的效果。