自动流按钮面板






4.59/5 (10投票s)
一个 .NET 控件,用于控制应用程序中分类区域的布局。
不要忘记投票。您的投票有助于不断添加新功能。
引言
在本文中,我将向您展示如何创建一个 .NET 控件,该控件可用于对应用程序中的各个部分进行分类。此控件还可以用于许多其他方式。只需查看源代码和演示以获得对其工作原理的总体了解,然后根据需要使用它。
如果您在使用此控件时遇到任何问题,或者想添加新功能、报告错误或提交您自己的更改,都欢迎您,我将很高兴为您提供帮助。
背景
创建此控件的想法是在一年前我开发一个教阿拉伯语用户英语的应用程序时产生的,当时我需要对应用程序的各个部分进行分类(学习、词汇、测试等)。我在网上搜索了这样的控件,但没有找到任何满足我需求的控件、代码或文章。所以我决定自己实现一个控件,并将代码放在这里供大家使用。
工作原理
此控件的基石是了解按钮及其面板如何排列;这是通过特定的步骤完成的,这些步骤是:
- 我们知道每个按钮都有一个与之关联的面板
- 我们将我们控件的所有按钮放入一个
list
类中 - 我们将第一个按钮的顶部设置为 0
- 我们将第一个按钮的面板的顶部设置为第一个按钮的底部 + 1
- 每个新按钮都应放置在上一个按钮的面板底部
- 我们进行一个循环来检查并查看每个按钮关联的面板是否可见,如果可见,我们将下一个按钮的顶部设置为该面板的底部,如果面板不可见,我们将下一个按钮的顶部设置为按钮本身的底部。
MultiView、SingleView 样式和 ArrangeAll 方法
在 MultiView
样式中,用户可以浏览和查看一个或多个面板的内容;在 SingleView
样式中,用户只能浏览和查看一个面板的内容。
ArrangeAll
方法根据上述步骤排列我们列表中的所有按钮,但有一个例外,即:在 MultiView
样式中,用户可以同时浏览多个面板;在 SingleView
样式中,用户一次只能浏览一个面板,因此在 SingleView
中,我们必须创建一个变量来存储先前查看过的按钮,并使用该变量隐藏先前查看过的面板,然后再显示新的面板内容。因此,当用户单击按钮时,ArrangeAll
方法会在该按钮的 OnClick
事件上被调用,我们将该按钮发送给 ArrangeAll
方法。该方法执行以下操作:如果样式是 MultiView
,并且处于 Visible
状态,如果发送按钮的面板为 false
,那么
- 将发送按钮面板的
Visible
状态设置为true
- 否则,将发送按钮面板的
Visible
状态设置为false
- 应用上面提到的第六步
- 如果样式是
SingleView
- 如果发送按钮面板的
Visible
状态为false
,那么 - 将发送按钮面板的
Visible
状态设置为true
- 否则,将发送按钮面板的
Visible
状态设置为false
- 隐藏先前查看过的按钮的面板 (因为我们一次只需要显示一个面板)
- 应用上面提到的第六步
考虑这段代码:
Friend Sub ArrangeAll(ByVal sender As YSSPButton, ByVal e As System.EventArgs)
If PanelVariables.LayoutVeiw = LayoutView.MultiView Then
Dim C As YSSPButton
sender.InnerPanel.Visible = Not sender.InnerPanel.Visible
sender.InnerPanel.Top = sender.Bottom + 1
For I As Int16 = 1 To Buttons.Count - 1
C = InnerFlowButtons(I - 1)
If Not C Is Nothing Then
If C.InnerPanel.Visible = True Then
InnerFlowButtons(I).Top = C.InnerPanel.Bottom + 1
' put the button after the previous button's panel
Else
InnerFlowButtons(I).Top = C.Bottom + 1
' put the button after the previous button
End If
End If
InnerFlowButtons(I).InnerPanel.Top = InnerFlowButtons(I).Bottom + 1
' every panel must be placed directly after its button
Next
Else
If sender.InnerPanel.Visible = True Then Return
' in single view if current visible button is clicked
' there is no need to arrange all buttons
Dim C As YSSPButton
' to let the user see panel contents
sender.InnerPanel.Visible = True
' every panel must be placed directly after its button
sender.InnerPanel.Top = sender.Bottom + 1
' hide the panel of the previous viewed button
PreViewedButton.InnerPanel.Visible = False
' every panel must be placed directly after its button
PreViewedButton.InnerPanel.Top = sender.Bottom + 1
If PanelVariables.LayoutVeiw = _
WindowsApplication2.YSSPAutoFlowButtonsPanel.LayoutView.SingleView Then
If PanelVariables.ButtonsStyle = _
WindowsApplication2.YSSPAutoFlowButtonsPanel.ButtonsStyle.Graphical Then
PreViewedButton.BackgroundImage = StateImages.MainImage
' set the image of the previous viewed button
' to the main state image not the seleced state image
End If
End If
PreViewedButton = sender ' to be used in the next call
For I As Int16 = 1 To Buttons.Count - 1
C = InnerFlowButtons(I - 1)
If Not C Is Nothing Then
If C.InnerPanel.Visible = True Then
InnerFlowButtons(I).Top = C.InnerPanel.Bottom + 1
' put the button after the previous button's panel
Else
InnerFlowButtons(I).Top = C.Bottom + 1
' put the button after the previous button
End If
End If
InnerFlowButtons(I).InnerPanel.Top = InnerFlowButtons(I).Bottom + 1
' every panel must be placed directly after its button
Next
End If
End Sub
Using the Code
我们的类这里包含一些其他类来控制其样式和行为,这些类是:
YSSPAutoFlowButtonsPanel
:这是面板本身的类。PanelVariables
:此类包含可应用于所有内部面板和按钮的通用信息,这些设置用于添加具有与主面板中其他按钮和面板相同样式的新按钮和内部面板。Buttons
:此类用于为单个按钮应用以下设置;如果您想将设置应用于所有按钮,可以使用ButtonsSettings
类。
Public Sub Add(ByVal Button As YSSPButton)
' these methods are not tested or debuged yet
Public Sub Remove(ByVal index As Integer)
Public Sub Remove(ByVal Button As YSSPButton)
Public Sub Hide(ByVal Index As Integer)
Public ReadOnly Property Count() As Integer
Public Sub SetWidth(ByVal Index As Integer, ByVal Width As Integer)
Public Sub SetHeight(ByVal Index As Integer, ByVal Height As Integer)
Public Sub Insert(ByVal Index As Integer, ByVal Button As YSSPButton)
Public Sub InsertRange(ByVal Start As Integer, ByVal Buttons As List(Of YSSPButton))
Public Sub Clear()
此类尚未完全实现或经过测试,还需要更多工作;如果您想实现此类,欢迎您。
Panels
:此类用于为单个面板应用以下设置;如果您想将设置应用于所有面板,可以使用 PanelsSettings
类。Public Sub SetPanelWidth(ByVal Index As Integer, ByVal Width As Integer)
Public Sub SetPanelHeight(ByVal Index As Integer, ByVal Height As Integer)
此类尚未完全实现或经过测试,还需要更多工作;如果您想实现此类,欢迎您。
ButtonsSettings
:此类用于将以下设置应用于所有按钮;如果您想将设置应用于单个按钮,可以使用 Buttons
类。Font
Cursor
ForeColor
BackColor
Width
Height
Left
RightToLeft
ImageAlign
ImageIndex
ImageKey
ImageList
TextAlign
TextImageRelation
Parent
PanelsSettings
:此类用于将以下设置应用于所有面板;如果您想将设置应用于单个面板,可以使用 Panels
类。BackgroundImage
BackgroundImageLayout
Cursor
ForeColor
BackColor
Height
width
Left
RightToLeft
Parent
Settings
:此类用于获取或设置主面板的常规设置。StateImages
:此类用于为内部按钮的不同状态提供图像。LayoutView
:此类用于设置或获取面板的布局视图。SingleView ' only one category can be viewed
MultiView ' many categories can be viewed at the same time
ButtonsStyle
:此类用于获取或设置内部按钮的样式。Graphical ' graphical style
Colors ' not implemented yet
System ' system style
YSSPButton
:此类是我们在控件中使用的按钮;它继承自 Button
类并重写了以下子程序。Protected Overrides Sub OnParentChanged(ByVal e As System.EventArgs)
MyBase.OnParentChanged(e)
InnerPanel.Parent = Me.Parent
' change the innerpanel's parent to the button's parent
End Sub
Protected Overrides Sub OnLocationChanged(ByVal e As System.EventArgs)
MyBase.OnLocationChanged(e)
InnerPanel.Top = Me.Bottom + 1
' every panel must be placed directly after its button
End Sub
Protected Overrides Sub OnSizeChanged(ByVal e As System.EventArgs)
MyBase.OnSizeChanged(e)
InnerPanel.Top = Me.Bottom + 1
' every panel must be placed directly after its button
End Sub
Protected Overrides Sub OnMouseEnter(ByVal e As System.EventArgs)
'return if this button is the selected one (Don't change its state)
If PanelVariables.ButtonsStyle = ButtonsStyle.Graphical Then
If PanelVariables.LayoutVeiw = LayoutView.SingleView Then
If PanelVariables.ButtonsStyle = ButtonsStyle.Graphical Then
If Me.InnerPanel.Visible = True Then
Exit Sub
End If
End If
End If
Me.BackgroundImage = StateImages.OverImage
End If
MyBase.OnMouseEnter(e)
End Sub
Protected Overrides Sub OnMouseLeave(ByVal e As System.EventArgs)
MyBase.OnMouseLeave(e)
If PanelVariables.ButtonsStyle = ButtonsStyle.Graphical Then
'return if this button is the selected one (Don't change its state)
If PanelVariables.ButtonsStyle = ButtonsStyle.Graphical Then
If PanelVariables.LayoutVeiw = LayoutView.SingleView Then
If PanelVariables.ButtonsStyle = ButtonsStyle.Graphical Then
If Me.InnerPanel.Visible = True Then
Exit Sub
End If
End If
End If
End If
Me.BackgroundImage = StateImages.MainImage
End If
End Sub
Protected Overrides Sub OnMouseDown(ByVal mevent As System.Windows.Forms.MouseEventArgs)
If PanelVariables.ButtonsStyle = ButtonsStyle.Graphical Then
'return if this button is the selected one (Don't change its state)
If PanelVariables.ButtonsStyle = ButtonsStyle.Graphical Then
If PanelVariables.LayoutVeiw = LayoutView.SingleView Then
If PanelVariables.ButtonsStyle = ButtonsStyle.Graphical Then
If Me.InnerPanel.Visible = True Then
Exit Sub
End If
End If
End If
End If
Me.BackgroundImage = StateImages.DownImage
End If
MyBase.OnMouseDown(mevent)
End Sub
Protected Overrides Sub OnMouseUp(ByVal mevent As System.Windows.Forms.MouseEventArgs)
If PanelVariables.ButtonsStyle = ButtonsStyle.Graphical Then
'return if this button is the selected one (Don't change its state)
If PanelVariables.ButtonsStyle = ButtonsStyle.Graphical Then
If PanelVariables.LayoutVeiw = LayoutView.SingleView Then
If PanelVariables.ButtonsStyle = ButtonsStyle.Graphical Then
If Me.InnerPanel.Visible = True Then
Exit Sub
End If
End If
End If
End If
Me.BackgroundImage = StateImages.OverImage
End If
MyBase.OnMouseUp(mevent)
End Sub
Protected Overrides Sub OnClick(ByVal e As System.EventArgs)
MyBase.OnClick(e)
' if this button is the selected one set its
' background image to StateImages.SelecedImage image
If PanelVariables.LayoutVeiw = LayoutView.SingleView Then
If PanelVariables.ButtonsStyle = ButtonsStyle.Graphical Then
If Me.InnerPanel.Visible = True Then
Me.BackgroundImage = StateImages.SelecedImage
End If
End If
End If
End Sub
您可以浏览源代码以了解其工作原理。如果您想编写和测试 Buttons
和 Panels
类,您可以这样做,并将您的更改发送给我,以便添加到本文中并完成此控件。
关注点
您知道吗,当我决定编写这个控件时,只用了半个小时就写完了代码并进行了测试,而当我决定在这里的 CodeProject 上写它时,却花了一年时间!!!别问我为什么。
历史
- 2011 年 9 月 27 日:修复了源代码中的两个错误(已更新文章和源代码文件)。