Don't forget to vote. Your vote helps to keep adding features.
Introduction
In this article, I will show you how to create a .NET control that can be used to categorize sections in your application. This control can also be used in many other ways.
Just look at the source code and the demo to get a general view of how it works, then use it the way you like.
If you have any problems with this control or you want to add a feature, report a bug, or you want to submit your own changes, you are welcome and I will be happy to help you.
Background
The idea to create this control came to me an year ago when I was developing an application to teach English for Arabic users, and I needed to categorize the sections
of my application (study, vocabulary, tests, and so on). I searched the internet for such a control, but I didn't find any control, code, or article that met my needs.
So I decided to implement a control myself and put its code here to be available for everyone.
How it works
The corner stone of this control is to know how buttons and their panels are arranged; this is done in certain steps and these steps are:
- we know that every button has a panel associated with it
- we put all the buttons of our control into a
list
class - we set the first button's top to 0
- we set the first button's panel's top to the bottom of the first button + 1
- every new button should be placed at the bottom of the panel of the button that precedes it
- we do a loop to check and see if the panel associated to every button is visible or not, and if it is visible, we set the next button's top to the bottom of that panel,
and if the panel is not visible, we set the next button's top to the bottom of the button itself.
MultiView, SingleView styles and ArrangeAll method
In the MultiView
style, the user can explore and see the contents of one or more panels;
in the SingleView
style, the user can explore and see the contents of only one panel.
The ArrangeAll
method arranges all the buttons in our list according to the steps mentioned above, but with an exception,
and this exception is: in the MultiView
style, the user can explore more than one panel at a time, and in the SingleView
style, the user can explore only one panel
at a time, so in SingleView
, we must create a variable to store the previously viewed button and use that variable to hide the previously viewed panel
before we show the new panel contents, so when the user clicks a button, the ArrangeAll
method is called on the OnClick
event of that button
and we send that button to the ArrangeAll
method. The method does the following: if the style is MultiView
, in the Visible
state,
if the the sender button's panel is false
, then:
- set the
Visible
state of the the sender button's panel to true
- and if not, set the
Visible
state of the the sender button's panel to false
- apply the sixth step mentioned above
- if the style is
SingleView
- if the
Visible
state of the sender button's panel is false
then:
- set the
Visible
state of the sender button's panel to true
- and if not, set the
Visible
state of the sender button's panel to false
- hide the previously viewed button's panel (because we need only one panel to be viewed a time)
- apply the sixth step mentioned above
Consider this code:
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
Else
InnerFlowButtons(I).Top = C.Bottom + 1
End If
End If
InnerFlowButtons(I).InnerPanel.Top = InnerFlowButtons(I).Bottom + 1
Next
Else
If sender.InnerPanel.Visible = True Then Return
Dim C As YSSPButton
sender.InnerPanel.Visible = True
sender.InnerPanel.Top = sender.Bottom + 1
PreViewedButton.InnerPanel.Visible = False
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
End If
End If
PreViewedButton = sender
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
Else
InnerFlowButtons(I).Top = C.Bottom + 1
End If
End If
InnerFlowButtons(I).InnerPanel.Top = InnerFlowButtons(I).Bottom + 1
Next
End If
End Sub
Using the Code
Our class here contains some other classes to control its style and behavior, and these classes are:
YSSPAutoFlowButtonsPanel
: this is the class of the panel itself.PanelVariables
: this class contains general information that can be applied to all inner panels and buttons, and these settings are used to add new buttons
and inner panels with the same style of the other buttons and panels currently inside the main panel.Buttons
: this class is used to apply the following settings to an individual button; if you want to apply a setting to all buttons,
you can do it using the ButtonsSettings
class.
Public Sub Add(ByVal Button As YSSPButton)
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()
This class is not fully implemented or tested and needs more work; if you like to implement this class, you are welcome.
Panels
: this class is used to apply the following settings to an individual panel; if you want to apply a setting to all panels,
you can do it using the PanelsSettings
class.
Public Sub SetPanelWidth(ByVal Index As Integer, ByVal Width As Integer)
Public Sub SetPanelHeight(ByVal Index As Integer, ByVal Height As Integer)
This class is not fully implemented or tested and needs more work; if you like to implement this, class you are welcome.
ButtonsSettings
: this class is used to apply the following settings to all buttons; if you want to apply a setting to an individual button,
you can do so using the Buttons
class.
Font
Cursor
ForeColor
BackColor
Width
Height
Left
RightToLeft
ImageAlign
ImageIndex
ImageKey
ImageList
TextAlign
TextImageRelation
Parent
PanelsSettings
: this class is used to apply the following settings to all panels; if you want to apply a setting to an individual panel,
you can do so using the Panels
class.
BackgroundImage
BackgroundImageLayout
Cursor
ForeColor
BackColor
Height
width
Left
RightToLeft
Parent
Settings
: this class is used to get or set the general settings for the main panel.StateImages
: this class is used to provide images for different states for inner buttons.LayoutView
: this class is used to set or get the layout view of the panels.
SingleView
MultiView
ButtonsStyle
: this class is used to get or set the style of the inner buttons.
Graphical
Colors
System
YSSPButton
: this class is the button used in our control; it inherits the Button
class and overrides the following subs:
Protected Overrides Sub OnParentChanged(ByVal e As System.EventArgs)
MyBase.OnParentChanged(e)
InnerPanel.Parent = Me.Parent
End Sub
Protected Overrides Sub OnLocationChanged(ByVal e As System.EventArgs)
MyBase.OnLocationChanged(e)
InnerPanel.Top = Me.Bottom + 1
End Sub
Protected Overrides Sub OnSizeChanged(ByVal e As System.EventArgs)
MyBase.OnSizeChanged(e)
InnerPanel.Top = Me.Bottom + 1
End Sub
Protected Overrides Sub OnMouseEnter(ByVal e As System.EventArgs)
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
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
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
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 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
You can explore the source code to see how it works. If you want to write and test the Buttons
and Panels
classes, you can do so and send me
your changes to add to this article and get this control completed.
Points of interest
Do you know that when I decided to write this control, it took only half an hour to write the code and test it and when I decided
to write it here on CodeProject, it took an year!!! Don't ask me why.
History
- 27 Sep 2011: Fixed two mistakes in the source code (article and source code files have been updated).