Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

TabControl with Pop Out Windows

0.00/5 (No votes)
4 May 2018 1  
This article present code that implements a tab control with pop out windows

Introduction

First of all, the code is predicated on the code developed by Pritam Zope and can be found here.

I just added features that I require for the tab control to be usable in my application.

Background

I have an old program that I decided to upgrade to current standards and use MVC architecture. Looking through CodeProject, I ran across Pritam's article which did some of what I needed to do in regards to the 'V' part of MVC. However, I needed more.

  1. Each control in the tab window must be able to pop out of and return back to the tab control regardless of how deep the tab structures go.
  2. Show that each tab control can perform properly using the MVC linkage methods in either docked or floating state.
  3. Have a higher 'eye candy' factor than just plain square tab buttons.
  4. Variable Width Buttons.

This article presents what I came up with.

Tabs fully docked

Tabs undocked

Using the Code

Again, this code is fully based on the work done by Pritam Zope, so please refer back to his article on how the tab control is implemented.

Popping Windows

Moving controls from one container to another container is very simple. It's just a matter of moving the control to another container, then removing it from the original location. In this code, the '^' symbol in the tab line will pop the selected tab to a floating window.

  1. Make sure there's a tab to pop
  2. Create new window, set its title and the Tag to the owning TabControl
  3. Add the control to Form.Controls and show
  4. Remove control from original location
private void toolStripLabel1_Click(object sender, EventArgs e)
{
    if (_selectedIndex < 0) return;
    var frm = new FormTab
    {
        Text = _buttonlist[_selectedIndex].DisplayText,
        Tag = this
    };
    frm.Controls.Add(_tabPanelCtrlList[_selectedIndex]);
    frm.Show();
    RemoveTab(_selectedIndex);
}

Reversing this process returns the control back to the tab structure. In FormTab.cs, you will find:

private void FormTab_FormClosed(object sender, FormClosedEventArgs e)
{
    if (Tag.GetType() != typeof(TabControlX)) return;
    var tc = (TabControlX)Tag;
    var tpc = new TabPanelControl { Dock = DockStyle.Fill };
    tpc.Controls.Add(Controls[0]);
    tc.AddTab(Text, tpc);
}

I design my controls using a Form with the exception that Form.Controls must have only one control in it. This control can be a Panel, DataGridView, SplitterContainer or anything you can place other controls into. For this demo, the top control in FormMonitor, FormConnection are Panels with other controls placed inside the panels.

Once everything is configured and tested in the form, it can be used to create the tab pages as shown below. Here, we see the FormConnection being instantiated and its top control being moved to the tab page. Hitting the Close box on the window will de-pop it.

private void button4_Click(object sender, EventArgs e)
    {
        var tpc = new TabPanelControl();
        var conn = new FormConnection();
        tpc.Controls.Add(conn.Controls[0]);
        tabControlX1.AddTab(conn.Text, tpc);
        .
        .
        .
    }

Yes, I could have developed these controls as UserControls and drop them down onto the tab page but I just find it easier to design and test this way.

MVC Linkage

Normally, views get model change events that update the view. To emulate these events, I just implemented a simple timer which on the timer tick changes the view as if a model event was triggered. Monitor, Connections, and DataGrid view are active whether they are in a tab page or popped out to a window.

Try it by popping the pages off and on the tabcontrol. Verify that the controls are still updating regardless of where they are located.

Eye Candy Factor

As Pritam stated in one of the comments, he created this demo to "creating your own tabcontrol from scratch". In my opinion, square buttons for tabs just don't meet my eye candy factor requirements. So I went ahead and modified ButtonX.cs to include top rounded buttons with gradient fills. All of this can be customized as you see fit.

Variable Width Buttons

I didn't like the fixed button width so I added the following code to CreateAndAddButton function in TabControlX.cs. Basically, it creates a device context handle and uses TextRender.MeasureText to figure out how wide to make the button to contain the text.

private void CreateAndAddButton(string tabtext, TabPanelControl tpcontrol, Point loc)
{
    var dc = CreateGraphics();
    var t = TextRenderer.MeasureText(dc, tabtext, Font);
    var bx = new ButtonX
    {
        DisplayText = tabtext,
        Text = tabtext,
        Size = new Size(t.Width + 20, 30),
        Location = loc,
        TextLocationX = 10,
        TextLocationY = 9,
        Font = Font
    };
    .
    .
    .

History

  • 5th May, 2018: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here