Click here to Skip to main content
11,924,487 members (57,404 online)
Click here to Skip to main content
Add your own
alternative version


265 bookmarked

A highly configurable MDI tab control from scratch

, 4 Jul 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
A completely configurable tab control to use as tabbed MDI forms.

Sample Image - MDITabControl.png


Instead of fighting with the Forms.TabControl, I thought that writing one from scratch should be a lot of fun. My goal was to produce a tab control with specific behaviours, and simple to use, and at the same time, with explorer inheritance, graphics, delegation, and collections.

This tab control is specific to creating a MDI interface with one tab page for each form. Some of the behaviours that were implemented are:

  • Always open the new page at the first tab
  • Hide the tab pages that can't fit in the screen
  • Don't scroll tab pages, instead, bring a hidden tab page to the first position when it's selected
  • Have a list of the tab pages (forms) in a drop down menu
  • Ability to reorder tabs by dragging
  • Easy owner draw
  • Close button at the tab
  • Clicking on overlapped part of the tab does not select the other tab and also
  • Clicking outside the border doesn't select the tab (achieved by the Region property)
  • Expose the maximum of functionality and configurability as possible
  • Very simple to use

What this is not

Well, this is not a docking panel. Also, there is some functionality that wasn't implemented like left/right Alignment, RightToLeft, support to add tab pages at design time (what doesn't really make sense in this case), container tab pages, and others.

This is not a very fast control, since I exposed a lot of functionality/customizations, but did my best to be OK and look cool.

What can be customized

Almost everything. To understand the control, let's take a look at the objects and regions.

  • The first two lines are the TopSeparator
  • Followed by the TabTop
  • On the left the Tabs area
  • On the right the Control Buttons area
  • The space between the tabs is the TabOffset
  • All the bottom part is the form

The tab is composed of the following areas from left to right:

  • TabPadLeft
  • Icon
  • Text
  • CloseButton
  • TabPadRight

Most customizations are made through properties. All the properties are in the TabControl, and some of them are in the TabPage, so you can change some appearance on each specific tab.

The icon and the text in the tab are the Icon and Text properties of the form, respectively. All the colors in the control can be changed. The close button in the tab can be replaced by an image. The TopSeparator, the tab icon, the tab Close button, and the control buttons can be displayed or not. And there is a lot more. Look at the control to see what’s possible.

The tab shape can be changed by the GetTabRegion event. The tab background can be OwnerDraw by the event TabPaintBackGround, and the border can be handled by the event TabPaintBorder. The events occur in the order mentioned.

Using the control

To use the control, you first need to add it to a form. Ideally, you should dock the control in it.

After that, you can change all the properties through the designer.

To insert a TabPage (form) in the control:

' Create the form
Dim MyForm As New AnyForm

' Insert the provided form in the TabControl1
' and save the TabPage in the Form.Tag property
MyForm.Tag = TabControl1.TabPages.Add(MyForm)

You don't show the form, instead you just add it to the control. Very simple, isn't it? On an existing program, you just need to add the control to the main form, and where you have the Show call for the form, you just replace by the Add method.

' replace the actual call by the new one
' MyForm.Show

You will probably not need to change any property in your form. The Add method changes the necessary ones.

TabControl.TabPages.Add is a function that returns the created TabPage. You can save it to a variable, or you can ignore the returned value. In the example above, I saved the TabPage in the Form.Tag property, this is a good Idea if you want to have a fast access to the TabPage.

To activate an existing form in the control:

' You can use the TabPage
DirectCast(MyForm.Tag, MdiTabControl.TabPage).Select()

'or just use the form

You can access a tab page by the Index or by the Form, and you can get the Index by the TabPage or by the Form.

To change the tab shape:

Private Sub TabControl2_GetTabRegion(ByVal sender As Object, ByVal e As _
        MdiTabControl.TabControl.GetTabRegionEventArgs) _
        Handles TabControl2.GetTabRegion
    ' you can create a new point array or just modify the existing one
    e.Points(1) = New Point(e.TabHeight - 2, 2)
    e.Points(2) = New Point(e.TabHeight + 2, 0)
End Sub

This example above changes the default shape to the colourful one in the first picture.

To OwnerDraw the tab background:

Private Sub TabControl1_TabPaintBackground(ByVal sender As Object, ByVal e As _
        MdiTabControl.TabControl.TabPaintEventArgs) _
        Handles TabControl1.TabPaintBackground
    ' Say to the control to don't paint the background
    e.Handled = True

    ' here add your code to paint the background
    ' the TabPaintEventArgs has several properties to help

End Sub

To OwnerDraw the tab border:

Private Sub TabControl1_TabPaintBorder(ByVal sender As Object, ByVal e As _
        MdiTabControl.TabControl.TabPaintEventArgs) _
        Handles TabControl1.TabPaintBorder

' Say to the control to don't paint the border
    e.Handled = True

    ' here add your code to paint the background
    ' the TabPaintEventArgs has several properties to help

End Sub

You can leave the Handled property set to false so the control will draw the border, but you can do some extra painting after the control has painted the background and before the border painting, as you can see in the "MY MDI Form #2" tab in the first picture.

Inside the code

The class TabPage inherits from System.Windows.Forms.Control. The control itself is the tab, and the form is an attribute of it. It exposes the Click event, which is fired when the tab is clicked/selected. There is no CloseClick event, since it is captured by the form Close event.

The class TabControl inherits from System.Windows.Forms.UserControl. This class has three internal classes. The GetTabRegionEventArgs is inherited from System.EventArgs, the TabPaintEventArgs inherited from PaintEventArgs, and the TabPageCollection inherited from CollectionBase.

Also, there is the Friend class ControlButton inherited from System.Windows.Forms.Control that is used by the DropButton and the global CloseButton.

The Close button in the tab is not a contained control. It's part of the control itself and is controlled by the tab's mouse events.


Some enhancements and some changes to the original version. The file LastChanges.txt on the zip file has what's changed.

The new property TabGlassGradient deserves a comment here. My solution for the Glass Look that's on Firefox tabs and IE 7 tabs was pretty simple. I get the gradient from two colors, cut the gradient in 1/3, and invert the bottom. I don't know how the others are doing it, but works fine this way. Here is the code.

' returns a new gradient brush with the glass look
Friend Function CreateGlassGradientBrush( _
       ByVal Rectangle As Rectangle, ByVal Color1 As Color, _
       ByVal Color2 As Color) As Drawing2D.LinearGradientBrush
    ' creates a new gradient brush
    Dim b As New Drawing2D.LinearGradientBrush(Rectangle, _
    Color1, Color2, Drawing2D.LinearGradientMode.Vertical)
    ' creates a new bitmap to to render the gradient
    Dim x As New Bitmap(1, Rectangle.Height)
    Dim g As Graphics = Graphics.FromImage(x)
    ' paint the gradient on the bitmap
    g.FillRectangle(b, New Rectangle(0, 0, 1, Rectangle.Height))
    ' create a new color blend with 4 colors and copy the
    ' colors from the bitmat 
    Dim c As New Drawing2D.ColorBlend(4)
    c.Colors(0) = x.GetPixel(0, 0)
    c.Colors(1) = x.GetPixel(0, x.Height / 3)
    ' the trick is here the 3rd color is the last color in
    ' the bitmap
    c.Colors(2) = x.GetPixel(0, x.Height - 1)
    ' and the last color is the one at 1/3
    c.Colors(3) = x.GetPixel(0, x.Height / 3)
    c.Positions(0) = 0
    c.Positions(1) = 0.335
    c.Positions(2) = 0.335
    c.Positions(3) = 1
    ' assign the color blend to the brush
    b.InterpolationColors = c
    Return b
End Function

Don't forget to recompile before opening the main form on the test project.

That's it for now. I'm gonna have a diet Pepsi!


  • July 04, 2011: Updated download file.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Eduardo Oliveira
Software Developer (Senior)
Canada Canada
Eduardo Oliveira graduated in Computer Systems Analysis in Rio de Janeiro - Brazil in 1990.
He has been working as Programmer Analyst since.
In 2001 immigrated to Canada and today lives in Calgary and works with .NET and SQL server, developing desktop and web applications.

You may also be interested in...

Comments and Discussions

QuestionDatagridview Problem Pin
Member 476126219-May-15 7:53
memberMember 476126219-May-15 7:53 
AnswerRe: Datagridview Problem Pin
Member 476126219-May-15 10:43
memberMember 476126219-May-15 10:43 
QuestionOpen tab from another form Pin
Capsulecorp12-May-15 7:44
memberCapsulecorp12-May-15 7:44 
AnswerRe: Open tab from another form Pin
Member 476126220-Jul-15 3:48
memberMember 476126220-Jul-15 3:48 
Questionchange the opening direction Pin
Member 963042311-Mar-15 20:45
memberMember 963042311-Mar-15 20:45 
AnswerRe: change the opening direction Pin
Member 963042312-Mar-15 3:31
memberMember 963042312-Mar-15 3:31 
GeneralRe: change the opening direction Pin
Antonio_cadiz19-Mar-15 4:32
memberAntonio_cadiz19-Mar-15 4:32 
GeneralRe: change the opening direction Pin
kalicem19-Mar-15 5:38
memberkalicem19-Mar-15 5:38 
GeneralRe: change the opening direction Pin
Ahmed Aboelez21-Nov-15 1:05
memberAhmed Aboelez21-Nov-15 1:05 
QuestionHow to activate already selected tab? Pin
susindharan27-Jan-15 20:03
membersusindharan27-Jan-15 20:03 
SuggestionNew Tab Button Pin
Member 1085700124-Oct-14 21:57
memberMember 1085700124-Oct-14 21:57 
GeneralRe: New Tab Button Pin
Member 963042312-Mar-15 11:08
memberMember 963042312-Mar-15 11:08 
QuestionHow to add a scroll button to scroll next or back like a browser ? Pin
Member 1023402519-Jul-14 2:37
memberMember 1023402519-Jul-14 2:37 
QuestionResizing problem... when main form (included MDI tab control) was resized Pin
Seongkyu LEE16-May-14 21:31
memberSeongkyu LEE16-May-14 21:31 
Answer[Solved] Re: Resizing problem... when main form (included MDI tab control) was resized Pin
Seongkyu LEE16-May-14 23:32
memberSeongkyu LEE16-May-14 23:32 
QuestionHow to make program close when last tab is closed Pin
Member 1074291413-Apr-14 8:17
memberMember 1074291413-Apr-14 8:17 
AnswerRe: How to make program close when last tab is closed Pin
kasbaba3-May-14 0:05
memberkasbaba3-May-14 0:05 
AnswerRe: How to make program close when last tab is closed Pin
ry sieł14-Nov-15 6:28
memberry sieł14-Nov-15 6:28 
Questionhow to make action on clic in tab title Pin
joel montero4-Feb-14 7:44
memberjoel montero4-Feb-14 7:44 
QuestionForm minimize problem Pin
Member 476126220-Jan-14 10:01
memberMember 476126220-Jan-14 10:01 
AnswerRe: Form minimize problem Pin
Member 476126220-Jan-14 10:02
memberMember 476126220-Jan-14 10:02 
GeneralHey dude !!! Such a long time, eh ? Pin
MaxRicardo2-Dec-13 17:43
memberMaxRicardo2-Dec-13 17:43 
QuestionForm.ShowIcon not working Pin
Ashley Charlton21-Nov-13 5:00
memberAshley Charlton21-Nov-13 5:00 
QuestionAutosize Pin
misterff116-Nov-13 4:08
membermisterff116-Nov-13 4:08 
AnswerRe: Autosize Pin
kalicem14-Mar-15 13:57
memberkalicem14-Mar-15 13:57 
QuestionWindows 8 Pin
Member 1039558911-Nov-13 21:49
memberMember 1039558911-Nov-13 21:49 
AnswerRe: Windows 8 Pin
misterff116-Nov-13 4:09
membermisterff116-Nov-13 4:09 
QuestionHow to get a list of Tab Names Pin
drkajun4-Oct-13 6:32
memberdrkajun4-Oct-13 6:32 
Questionkoding form close, for msgbox Pin
Member 1020576518-Aug-13 7:51
memberMember 1020576518-Aug-13 7:51 
Questionadd tab button on the left Pin
Primus2x26-Jul-13 5:10
memberPrimus2x26-Jul-13 5:10 
QuestionAtualizaçao Pin
hernany25-Jun-13 14:39
memberhernany25-Jun-13 14:39 
QuestionHow to change tab order Pin
Amila thennakoon21-Jun-13 2:22
memberAmila thennakoon21-Jun-13 2:22 
AnswerRe: How to change tab order Pin
misterff116-Nov-13 4:10
membermisterff116-Nov-13 4:10 
QuestionHelp me, no change BackColor or BackgroundImage??? Pin
khoinguyenit11-Apr-13 4:19
memberkhoinguyenit11-Apr-13 4:19 
QuestionCould you help me to understand this coding Pin
Amila thennakoon10-Mar-13 21:17
memberAmila thennakoon10-Mar-13 21:17 
QuestionMditabcontrol Pin
dagronzzan7-Oct-12 3:04
memberdagronzzan7-Oct-12 3:04 
AnswerRe: Mditabcontrol Pin
TheCrazyTim21-Feb-13 16:02
memberTheCrazyTim21-Feb-13 16:02 
GeneralRe: Mditabcontrol Pin
dagronzzan1-Apr-13 7:48
memberdagronzzan1-Apr-13 7:48 
Questionhow to make TabPage into TabGlassGradient Pin
sky391331-Aug-12 0:30
membersky391331-Aug-12 0:30 
Bughard bug! Pin
spiritdead13-Aug-12 20:51
memberspiritdead13-Aug-12 20:51 
GeneralRe: hard bug! Pin
Olivier Levrey13-Aug-12 22:39
memberOlivier Levrey13-Aug-12 22:39 
BugRe: hard bug! Pin
spiritdead14-Aug-12 13:16
memberspiritdead14-Aug-12 13:16 
GeneralRe: hard bug! Pin
Olivier Levrey16-Aug-12 3:24
memberOlivier Levrey16-Aug-12 3:24 
GeneralRe: hard bug! Pin
spiritdead16-Aug-12 11:41
memberspiritdead16-Aug-12 11:41 
Bugi cant see this functions .... Pin
spiritdead13-Aug-12 17:29
memberspiritdead13-Aug-12 17:29 
GeneralRe: i cant see this functions .... Pin
Olivier Levrey13-Aug-12 22:47
memberOlivier Levrey13-Aug-12 22:47 
GeneralRe: i cant see this functions .... Pin
spiritdead14-Aug-12 13:36
memberspiritdead14-Aug-12 13:36 
GeneralRe: i cant see this functions .... Pin
Olivier Levrey16-Aug-12 3:16
memberOlivier Levrey16-Aug-12 3:16 
Answerbug find, and fix :) Pin
spiritdead13-Aug-12 16:17
memberspiritdead13-Aug-12 16:17 
BugGreat job. A few Dispose are just missing. Pin
Olivier Levrey27-Jul-12 3:39
memberOlivier Levrey27-Jul-12 3:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.151125.3 | Last Updated 4 Jul 2011
Article Copyright 2006 by Eduardo Oliveira
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid