I recently had the need to add a few panels to a program that I have been working on. The panels did not need to be shown all the time and I didn't want to spawn a new form everytime I needed to see the extra panel. Additionally, I wanted the new panels to dock to the side of the main form so they would not cover the main content. My program needed three seperate areas, a debug window, options window, and of course the main window as shown in Figure 2.

Figure 1
After quite a bit of experimenting I decided to show/hide forms that were loaded with the main form. Another explored option was to use GDI+ to make graphic panels appear and disappear but in the end they were too complicated and I decided to go with the quicker and simplier approach. After getting several requests for code on this particular project I decided to create my own tutorial on how to make dockable pop-up forms in VB.NET.

Firgure 2
Structure
The project consists of three forms:
frmMain.vb - Main form for the project
frmDebug.vb - Add on pop-up
frmOptions.vb - Add on pop-up
The number of forms used can be modified. I started with just the debug form but later added functionality for an options form. The work of creating, showing, and docking the forms are split amoung the three forms.
frmDebug
If you have not already done so, the first thing to do is to add a new form to your project, in my case it is the debug form. The forms apprearence has nothing special about it except in my case I decided to remove the ControlBox from the title bar and set ShowInTaskbar to false.
In the frmDebug form create three global variables:
CODE
Private _myParent As New Form
Dim _bFormLock As Boolean
Dim ptFormLocation As New Point
Dim _bFormLock As Boolean
Dim ptFormLocation As New Point
The _myParent form represents a link back to the main form. This is need so that if the debug form is moved and the debug form is docked with the main form, the main form will also move.
_bFormLock holds a boolean value showing if the current form is docked.
ptFormLocation is a drawing point used for showing the location of the forms.
Next create two properties:
CODE
Public Property myparent() As Form
Get
Return _myParent
End Get
Set(ByVal Value As Form)
_myParent = Value
End Set
End Property
Public Property bFormLock() As Boolean
Get
Return _bFormLock
End Get
Set(ByVal Value As Boolean)
_bFormLock = Value
End Set
End Property
Get
Return _myParent
End Get
Set(ByVal Value As Form)
_myParent = Value
End Set
End Property
Public Property bFormLock() As Boolean
Get
Return _bFormLock
End Get
Set(ByVal Value As Boolean)
_bFormLock = Value
End Set
End Property
This of course provides a link between forms.
Add the LocationChanged function:
CODE
Private Sub frmDebug_LocationChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.LocationChanged
If bFormLock = True Then
ptFormLocation.X = (Me.Location.X - Me.myparent.Width)
ptFormLocation.Y = Me.Location.Y
Me.myparent.Location = ptFormLocation
End If
End Sub
If bFormLock = True Then
ptFormLocation.X = (Me.Location.X - Me.myparent.Width)
ptFormLocation.Y = Me.Location.Y
Me.myparent.Location = ptFormLocation
End If
End Sub
The LocationChanged function handles the task of moving the parent form (frmMain) if the child form (frmDebug) is moved and the two are docked. In this case you will notice that the x location is the width of the child from minus the width of the parent form. This puts the x location the width of the parent form to the left of the child form. The y location remains the same so the two forms will be even on the y-axis.
frmOptions
The options form is identical to the debug for with one exception, the LocationChanged function positions the form to the bottom of the child form. Notice that the function is similar except the x and y points have been changed.
CODE
Private Sub frmOptions_LocationChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.LocationChanged
If bFormLock = True Then
ptFormLocation.X = Me.Location.X
ptFormLocation.Y = Me.Location.Y - Me.myparent.Height
Me.myparent.Location = ptFormLocation
End If
End Sub
If bFormLock = True Then
ptFormLocation.X = Me.Location.X
ptFormLocation.Y = Me.Location.Y - Me.myparent.Height
Me.myparent.Location = ptFormLocation
End If
End Sub
frmDebug
The main form needs four buttons:
btnDebug - used to show the debug form
btnDebugDocking - dock the debug form
btnOptions - used to show the options form
btnOptionsDocking - dock the options form
Of course the main form is where everything is tied together. Add references for the debug and options form:
CODE
'Docking Forms
Friend WithEvents DebugForm As New frmDebug
Dim ptDebugFormLocation As Point
Shared bDebugFormLock As Boolean = True
'Options Form
Dim OptionsForm As New frmOptions
Dim ptOptionsFormLocation As Point
Shared bOptionsFormLock As Boolean = True
Friend WithEvents DebugForm As New frmDebug
Dim ptDebugFormLocation As Point
Shared bDebugFormLock As Boolean = True
'Options Form
Dim OptionsForm As New frmOptions
Dim ptOptionsFormLocation As Point
Shared bOptionsFormLock As Boolean = True
In my case I want the debug form to be shown as the program starts so I added an OnLoad function:
CODE
Protected Overrides Sub OnLoad(ByVal e As EventArgs)
frmDebug_Show()
End Sub
frmDebug_Show()
End Sub
The function LocationChanged, moves both child forms if the parent is moved.
CODE
Private Sub frmMain_LocationChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles MyBase.LocationChanged
If bDebugFormLock = True Then
ptDebugFormLocation.X = Me.Location.X + Me.Width
ptDebugFormLocation.Y = Me.Location.Y
DebugForm.Location = ptDebugFormLocation
End If
If bOptionsFormLock = True Then
ptOptionsFormLocation.X = Me.Location.X
ptOptionsFormLocation.Y = Me.Location.Y + Me.Height
OptionsForm.Location = ptOptionsFormLocation
End If
End Sub
ByVal e As System.EventArgs) _
Handles MyBase.LocationChanged
If bDebugFormLock = True Then
ptDebugFormLocation.X = Me.Location.X + Me.Width
ptDebugFormLocation.Y = Me.Location.Y
DebugForm.Location = ptDebugFormLocation
End If
If bOptionsFormLock = True Then
ptOptionsFormLocation.X = Me.Location.X
ptOptionsFormLocation.Y = Me.Location.Y + Me.Height
OptionsForm.Location = ptOptionsFormLocation
End If
End Sub
The function is similar to the code in the child forms except the minus is replaced by a plus function.
Two seperate event handlers are needed for each form. The creation of the debug child form:
CODE
Private Sub frmOptions_Show()
If OptionsForm.Visible = False Then
If bOptionsFormLock = True Then
ptOptionsFormLocation.X = Me.Location.X
ptOptionsFormLocation.Y = Me.Location.Y + Me.Height
OptionsForm.StartPosition = FormStartPosition.Manual
OptionsForm.Location = ptOptionsFormLocation
OptionsForm.Width = Me.Width
OptionsForm.bFormLock = True
End If
OptionsForm.Visible = True
OptionsForm.myparent = Me
Me.AddOwnedForm(OptionsForm)
OptionsForm.Show()
btnOptions.Text = "Options <<"
Else
OptionsForm.Visible = False
OptionsForm.bFormLock = False
btnOptions.Text = "Options >>"
End If
End Sub
If OptionsForm.Visible = False Then
If bOptionsFormLock = True Then
ptOptionsFormLocation.X = Me.Location.X
ptOptionsFormLocation.Y = Me.Location.Y + Me.Height
OptionsForm.StartPosition = FormStartPosition.Manual
OptionsForm.Location = ptOptionsFormLocation
OptionsForm.Width = Me.Width
OptionsForm.bFormLock = True
End If
OptionsForm.Visible = True
OptionsForm.myparent = Me
Me.AddOwnedForm(OptionsForm)
OptionsForm.Show()
btnOptions.Text = "Options <<"
Else
OptionsForm.Visible = False
OptionsForm.bFormLock = False
btnOptions.Text = "Options >>"
End If
End Sub
This handles the start location of the form and part of the docking buttons operation.
Next is the btnDebugDocking.Click event. This sets the property in the debug child form bFormLock. If true then the form will dock. If false the child from can be moved freely of its parent.
CODE
Private Sub btnDebugDocking_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnDebugDocking.Click
If bDebugFormLock = True Then ' To Unlock
bDebugFormLock = False
DebugForm.bFormLock = False
btnDebugDocking.Text = "L"
Else
bDebugFormLock = True 'To Lock
DebugForm.bFormLock = True
ptDebugFormLocation.X = Me.Location.X + Me.Width
ptDebugFormLocation.Y = Me.Location.Y
DebugForm.Location = ptDebugFormLocation
btnDebugDocking.Text = "U"
End If
ByVal e As System.EventArgs) _
Handles btnDebugDocking.Click
If bDebugFormLock = True Then ' To Unlock
bDebugFormLock = False
DebugForm.bFormLock = False
btnDebugDocking.Text = "L"
Else
bDebugFormLock = True 'To Lock
DebugForm.bFormLock = True
ptDebugFormLocation.X = Me.Location.X + Me.Width
ptDebugFormLocation.Y = Me.Location.Y
DebugForm.Location = ptDebugFormLocation
btnDebugDocking.Text = "U"
End If
The code for the options form is once again very similar to the debug form. The only difference is in the x and y-axis point needed to place the options form. Instead of located to the right, the form is located to the bottom.
Creation:
CODE
Private Sub frmOptions_Show()
If OptionsForm.Visible = False Then
If bOptionsFormLock = True Then
ptOptionsFormLocation.X = Me.Location.X
ptOptionsFormLocation.Y = Me.Location.Y + Me.Height
OptionsForm.StartPosition = FormStartPosition.Manual
OptionsForm.Location = ptOptionsFormLocation
OptionsForm.Width = Me.Width
OptionsForm.bFormLock = True
End If
OptionsForm.Visible = True
OptionsForm.myparent = Me
Me.AddOwnedForm(OptionsForm)
OptionsForm.Show()
btnOptions.Text = "Options <<"
Else
OptionsForm.Visible = False
OptionsForm.bFormLock = False
btnOptions.Text = "Options >>"
End If
End Sub
If OptionsForm.Visible = False Then
If bOptionsFormLock = True Then
ptOptionsFormLocation.X = Me.Location.X
ptOptionsFormLocation.Y = Me.Location.Y + Me.Height
OptionsForm.StartPosition = FormStartPosition.Manual
OptionsForm.Location = ptOptionsFormLocation
OptionsForm.Width = Me.Width
OptionsForm.bFormLock = True
End If
OptionsForm.Visible = True
OptionsForm.myparent = Me
Me.AddOwnedForm(OptionsForm)
OptionsForm.Show()
btnOptions.Text = "Options <<"
Else
OptionsForm.Visible = False
OptionsForm.bFormLock = False
btnOptions.Text = "Options >>"
End If
End Sub
btnOptionsDocking.Click:
CODE
Private Sub btnOptionsDocking_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnOptionsDocking.Click
If bOptionsFormLock = True Then ' To Unlock
bOptionsFormLock = False
OptionsForm.bFormLock = False
btnOptionsDocking.Text = "L"
Else
bOptionsFormLock = True 'To Lock
OptionsForm.bFormLock = True
ptOptionsFormLocation.X = Me.Location.X
ptOptionsFormLocation.Y = Me.Location.Y + Me.Height
OptionsForm.Location = ptOptionsFormLocation
btnOptionsDocking.Text = "U"
End If
End Sub
ByVal e As System.EventArgs) _
Handles btnOptionsDocking.Click
If bOptionsFormLock = True Then ' To Unlock
bOptionsFormLock = False
OptionsForm.bFormLock = False
btnOptionsDocking.Text = "L"
Else
bOptionsFormLock = True 'To Lock
OptionsForm.bFormLock = True
ptOptionsFormLocation.X = Me.Location.X
ptOptionsFormLocation.Y = Me.Location.Y + Me.Height
OptionsForm.Location = ptOptionsFormLocation
btnOptionsDocking.Text = "U"
End If
End Sub
Conclusion
I have found this code to be quite useful over several projects. In the future I may work on a GDI+ version of this project but that may be a ways down the road as this implemention works so well. Attached is the project that holds all the files needed for this project. Docking_Forms is written is Microsoft Visual Basic.NET 2003.

