Click here to Skip to main content
Click here to Skip to main content

TabStrip Control

, 30 May 2006 CPOL
Rate this:
Please Sign up or sign in to vote.
A flexible TabStrip control with basic design-time support.

Sample Image - tabstrips_demo.png

Introduction

With the introduction of .NET Framework 2.0, we have got a set of Strip controls, like MenuStrip and ToolStrip. They have rich design-time and run-time features and flexible interfaces. So the idea was to create a ToolStrip-like tab control supporting formatting in tab headers, animated icons, tab headers at any side, run-time tab reordering, tab grouping, and other stuff we miss in the Windows Forms TabControl.

Background

To implement the TabStrip and TabStripButton classes, we should use ToolStrip and ToolStripButton. Drawing should be performed via a ToolStripRenderer derived class - it's more flexible than painting in OnPaint. To use the current Windows XP theme, we ought to use methods from the System.Windows.Forms.VisualStyles namespace. The framework already wraps the uxTheme.dll, so we can go without a lot of P/Invoke calls.

We have to provide at least two ways for painting the interface: using visual styles, and without using them (we cannot use uxTheme on systems that don't support themes). So, let's add a theming check:

private bool useVS = Application.RenderWithVisualStyles;

/// <summary>
/// Returns if visual styles should be applied for drawing
/// <summary>
public bool UseVS
{
    get { return useVS; }
    set 
    {
        if (value && !Application.RenderWithVisualStyles)
            return;
        useVS = value; 
    }
}

ToolStrip generally has a few RenderModes: System, Professional, etc. So, if we want to paint an interface using any of them, we can either make derived classes from each Renderer class, or make one ToolStripRenderer derived class and use instances of the needed type within it. It will look like this:

private ToolStripRenderer currentRenderer = null;
private ToolStripRenderMode renderMode = ToolStripRenderMode.Custom;

/// <summary>
/// Gets or sets render mode for this renderer
/// </summary>
public ToolStripRenderMode RenderMode
{
    get { return renderMode; }
    set
    {
        renderMode = value;
        switch (renderMode)
        {
            case ToolStripRenderMode.Professional:
                currentRenderer = new ToolStripProfessionalRenderer();
                break;
            case ToolStripRenderMode.System:
                currentRenderer = new ToolStripSystemRenderer();
                break;
            default:
                currentRenderer = null;
                break;
        }
    }
}

Now, our toolbar's behavior should depend on its orientation. For this, we can use the ToolStrip.Orientation property. But it solves only one half of the problem. We still don't know at which side our TabStrip is docked. Theoretically, we can refer to the Dock and Parent properties to determine this, but in most cases, we know where our bar is located. So, we'll only make a property which determines if tab headers should be flipped.

private bool mirrored = false;

/// <summary>
/// Gets or sets whether to mirror background
/// </summary>
/// <remarks>Use false for left and top positions,
/// true for right and bottom</remarks>
public bool Mirrored
{
    get { return mirrored; }
    set { mirrored = value; }
}

The rest of the TabStripRenderer class is code for drawing, and nothing more interesting.

So we can go straight to the TabStripButton class. It extends the ToolStripButton with some new properties:

  • HotTextColor - Text color when mouse hovers TabStripButton.
  • SelectedTextColor - Text color when TabStripButton is SelectedTab.
  • SelectedFont - Font when TabStripButton is SelectedTab.
  • IsSelected - Gets or sets if tab is selected.

Also, we have to shadow the Checked, Padding, and Margin properties to avoid the user from breaking the pretty interface. These properties are also removed from the designer properties window.

Now, about the TabStrip class. It provides some new properties, most of them are wrappers for properties of the internal TabStripRenderer class.

  • UseVisualStyles - specifies if the system visual styles should be applied. If system does not support themes, this property is ignored, and the painting goes the custom way.
  • FlipButtons - specifies if the buttons should be drawn flipped. Set this to true if TabStrip should display tabs on the right or bottom side.
  • RenderStyle - property to use instead of RenderMode. Renderer and RenderMode are shadowed (for normal behavior), and removed from the designer property window.

Design-time support

First of all, we need to register TabStripButton as an available control for ToolStrip:

[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip)]
public class TabStripButton : ToolStripButton

Note that the class should be declared as public.

Designer view 1

Now, let's add the "Insert tab page" option in TabStrip's designer menu:

DesignerVerb insPage = null;

protected void InitControl()
{
    // ...
    // other initialization here
    // ...
    insPage = new DesignerVerb("Insert tab page", 
              new EventHandler(OnInsertPageClicked));
}

public override ISite Site
{
    get
    {
        ISite site = base.Site;
        if (site != null && site.DesignMode)
        {
            IContainer comp = site.Container;
            if (comp != null)
            {
                IDesignerHost host = comp as IDesignerHost;
                if (host != null)
                {
                    IDesigner designer = 
                       host.GetDesigner(site.Component);
                    if (designer != null && 
                          !designer.Verbs.Contains(insPage))
                        designer.Verbs.Add(insPage);
                }
            }
        }
        return site;
    }
    set
    {
        base.Site = value;
    }
}

protected void OnInsertPageClicked(object sender, EventArgs e)
{
    ISite site = base.Site;
    if (site != null && site.DesignMode)
    {
        IContainer container = site.Container;
        if (container != null)
        {
            TabStripButton btn = new TabStripButton();
            container.Add(btn);
            btn.Text = btn.Name;
        }
    }
}

The result looks like this:

Designer view 2

Summary

So, we have a new flexible control now. Unlike TabControl, it's not a container control, but it can be combined with other controls to simulate a container. And when tabs are needed for navigation, it leaves TabContol in the dust. And visual styles and rich picture support will make your application more cute and friendly.

History

  • 30.05.2006 - The very first version.

License

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

Share

About the Author

Messir
Web Developer
Russian Federation Russian Federation
Alex
.NET Developer
Russian Federation
rakemaker@gmail.com

Comments and Discussions

 
GeneralMy vote of 5 Pinmemberwhar27-Feb-12 8:37 
QuestionGood job PinmemberMike Hankey29-Aug-11 12:31 
GeneralImprovement PinmemberDominikF2-Dec-09 23:26 
GeneralC++ version PinmemberSuper Garrison7-Jul-09 8:32 
GeneralLicensing PinmemberJacek Gajek1-Jul-09 4:53 
Generalnice code, but has problem when I and a dropdownbutton Pinmemberchtoph10-May-09 17:04 
GeneralThanks a million PinmemberStringDotEmpty22-Mar-09 20:11 
GeneralThanks a million PinmemberPankajkumar Nikam9-Feb-09 19:46 
GeneralNeed some help Pinmemberimresoft1-Jul-08 4:22 
QuestionBeautiful... someone can write the same in vb.net ? Pinmemberwakashich29-Mar-08 22:09 
AnswerRe: Beautiful... someone can write the same in vb.net ? PinmemberThe Dogcow Farmer25-Jun-08 10:38 
GeneralClose button PinmemberGiorgi Dalakishvili26-Dec-07 23:57 
GeneralRe: Close button PinmemberAlpha Nerd7-May-08 0:22 
GeneralCtrl Tab PinmemberChris_McGrath23-Oct-07 18:56 
Generalearth to Alex PinmemberBillWoodruff5-May-07 9:14 
GeneralTabStrip.Designer.cs not found in project PinmemberAndrey Kaplun23-Apr-07 9:27 
General'Messir.Windows.Forms.TabStrip' assembly PinmemberGeert van Horrik22-Feb-07 5:50 
GeneralRe: 'Messir.Windows.Forms.TabStrip' assembly PinmemberGeert van Horrik24-Feb-07 3:19 
GeneralDamn good code. [modified] Pinmembersotona15-Feb-07 0:19 
GeneralLicensing PinmemberMattman20629-Jan-07 2:58 
QuestionBug? Pinmemberkarrphoto11-Jan-07 19:34 
AnswerRe: Bug? PinmemberElasticLink9-Oct-07 23:51 
Questioncombination with container control Pinmembermaorray11-Jan-07 3:10 
GeneralGreat PinmemberZapper.Net16-Aug-06 1:12 
QuestionBackground color? Pinmemberkrzychub3-Aug-06 23:10 
GeneralGreat work, guy! PinmemberYuri Ovchinnikov17-Jun-06 4:36 
Questionversion for .net 2003? Pinmembernetopeto9-Jun-06 7:07 
AnswerRe: version for .net 2003? PinmemberMessir14-Jun-06 6:55 
GeneralAnother Small Bug Pinmemberrsieiro9-Jun-06 6:21 
GeneralRe: Another Small Bug PinmemberHumble Programmer27-Jun-07 7:33 
Generalsmall bug Pinmemberhominoid7-Jun-06 19:33 
GeneralRe: small bug PinmemberMessir8-Jun-06 8:07 
GeneralSuper Pinmemberk_savelev5-Jun-06 23:25 
GeneralExcellent Work !!! PinmemberMarcos Meli31-May-06 12:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    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 | Mobile
Web04 | 2.8.141015.1 | Last Updated 30 May 2006
Article Copyright 2006 by Messir
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid