Click here to Skip to main content
Email Password   helpLost your password?

Sample Image

Introduction

Multi Document Interface (MDI) tab page browsing has been very popular among many Windows applications especially internet browsers such as Opera, Mozilla, Maxthon and many others. After failing to find an article on it, I decided to write one myself to show any interested reader that creating an MDI tab page browsing can be done with pretty simple but neat coding. All that is needed is a little creativity.

Using the code

The source code is a template of the tab page window application. The template can be used for creating a tab-page capable window program.

The code

First, in the parent form, set the IsMDIContainer property to true. Attach a TabControl component to the form and set the Dock property to Top.

Next, in the child form, create a non-initialized TabControl and a TabPage. Create a property for these two objects. Later, we will see that these two objects will contain references to the TabControl in the parent form and the corresponding child TabPage.

private TabControl tabCtrl;
private TabPage tabPag;

public TabPage TabPag
{
    get
    {
        return tabPag;
    }
    set
    {
        tabPag = value;
    }
}

public TabControl TabCtrl
{
    set
    {
        tabCtrl = value;
    }
}

When the MDI child form is closing, destroy the corresponding tab page.

private void MDIChild_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    //Destroy the corresponding Tabpage when closing MDI child form

    this.tabPag.Dispose();

    //If no Tabpage left

    if (!tabCtrl.HasChildren)
    {
        tabCtrl.Visible = false;
    }
}

When the MDI child form is activated, activate the corresponding tab page.

private void MDIChild_Activated(object sender, System.EventArgs e)
{
    //Activate the corresponding Tabpage

    tabCtrl.SelectedTab = tabPag;

    if (!tabCtrl.Visible)
    {
        tabCtrl.Visible = true;
    }
}

When the child form is created, add the reference values of the TabControl and TabPage to its fields.

private void NewMenuItem_Click(object sender, System.EventArgs e)
{
    //Creating MDI child form and initialize its fields

    MDIChild childForm = new MDIChild();
    childForm.Text = "MDIChild " + childCount.ToString();
    childForm.MdiParent = this;

    //child Form will now hold a reference value to the tab control

    childForm.TabCtrl = tabControl1;

    //Add a Tabpage and enables it

    TabPage tp = new TabPage();
    tp.Parent = tabControl1;
    tp.Text = childForm.Text;
    tp.Show();

    //child Form will now hold a reference value to a tabpage

    childForm.TabPag = tp;

    //Activate the MDI child form

    childForm.Show();
    childCount++;

    //Activate the newly created Tabpage

    tabControl1.SelectedTab = tp;
}

When a tab page is selected, activate its corresponding MDI child form.

private void tabControl1_SelectedIndexChanged(object sender, System.EventArgs e)
{
    foreach (MDIChild childForm in this.MdiChildren) 
    {
        //Check for its corresponding MDI child form

        if (childForm.TabPag.Equals(tabControl1.SelectedTab)) 
        {
            //Activate the MDI child form

            childForm.Select();
        }
    }
}

That's all!

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralA few modifications
see_seA
9:10 5 Jul '09  
I really did find this code useful, however I made a few adjustments. Basically the mdimain form should be the one controlling the tabs, and any child forms of any type should not know about what the main form is up to. This is very easy to accomplish.

        private void newMenuItem_Click(object sender, EventArgs e)
{
// creating MDI child form and initialize its fields
Form childForm = new Form();
childForm.Text = "MDIChild " + childCount++;
childForm.MdiParent = this;
childForm.Closing += childForm_Closing; // add a closing event
// add a TabPage and enable it
TabPage tp = new TabPage();
tp.Parent = tabControl;
tp.Text = childForm.Text;
tp.Tag = childForm; // hold a reference to the form
tp.Show();

// show the new form
childForm.Show();

// activate the newly created TabPage
tabControl.SelectedTab = tp;
tabControl.Visible = true;
}

void childForm_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
tabControl.SelectedTab.Dispose();

if (tabControl.TabCount <= 0)
tabControl.Visible = false;
}

private void tabControl_SelectedIndexChanged(object sender, EventArgs e)
{
// activate the child
if(tabControl.SelectedTab != null)
(tabControl.SelectedTab.Tag as Form).Activate();
}

By using the above logic, the child form does not need to know about the logic contained in the mdimain form which makes the code much cleaner.
Questionvery nice , how can i ?
shiva4it
20:27 3 Apr '08  
The concept is very nice . I need one thing.Whenever we make changes in the windows form of particular tab page, I want to show '*' attached to the form text (ie)'mdiChild1 *' on the tab. Is it possible and how can I attain that.Please send me the solution.
QuestionI want code snippet to close child form using menu
greatonkar
3:13 25 Oct '07  
I want code snippet to close child form using menu

I tried to close child form using code snippet:

Form activeChild = this.ActiveMDIChild;
if(activeChild != null)
{
activeChild.Close();
}

after this, child form closed along with tabcontrol
GeneralchildCount, FormClosing, and True tabbed layout
cipher_nemo
8:42 2 Oct '07  
Thanks for taking the time to write this. I usually don't use tabbed MDI for my apps, so this helped put me in the right mind set before I took off on my own.

Something I noticed...

The line that states, "When the MDI child form is closing, destroy the corresponding tab page.", should mention the "FormClosing" event, instead of just "closing". Developers new to .NET may get confused since the method "Cloe" exists, but the event "Closing" does not.

Also, the "childCount" isn't specified in your code. It is enough enough to figure out what to do here, but you don't include it. It's just an int property on the parent form that can start with a value of one:

private int childCount = 1;

One last thing: to use this as a tabbed MDI-like gui (true tabbed layout), we'd want to set all new child forms to maximized by default. Best way to do this is to have a GotFocus event for the child form:

private void MDIChild_GotFocus(object sender, System.EventArgs e)
{
this.WindowState = FormWindowState.Maximized;
}


Thanks! Smile

--
cipher_nemo (John)
Software Engineer
QuestionTwo predefined forms
bms7471
14:27 22 Feb '07  
I have two predefined forms that are in seperate classes. I want to open them as tabs in the MDIContainer. How would the SelectedIndexChanged method work? I can't get it to switch between the two tabs.

I have created an instance of each form and assigned them to their own tabs. like...

private static Indexing frmIndexingChild = new Indexing();

Where Indexing is the name of the Indexing form's class.
GeneralMore simple solution and support all child forms
Serdar YILMAZ
22:43 26 Jan '07  
Hi, Following code is more simple, more effective, support all child forms.
No any code necessary for child forms.
...
TabControl tabForms;
....

private void tabForms_SelectedIndexChanged(object sender, EventArgs e)
{
if ((tabForms.SelectedTab != null) && (tabForms.SelectedTab.Tag != null))
(tabForms.SelectedTab.Tag as Form).Select();
}

private void frmMain_MdiChildActivate(object sender, EventArgs e)
{
if (this.ActiveMdiChild == null)
tabForms.Visible = false; // If no any child form, hide tabControl
else
{
this.ActiveMdiChild.Width = 0; // Prevent form flicker
this.ActiveMdiChild.WindowState = FormWindowState.Maximized; // Child form always maximized

// If child form is new and no has tabPage, create new tabPage
if (this.ActiveMdiChild.Tag == null)
{
// Add a tabPage to tabControl with child form caption
TabPage tp = new TabPage(this.ActiveMdiChild.Text);
tp.Tag = this.ActiveMdiChild;
tp.Parent = tabForms;
tp.Show();

this.ActiveMdiChild.Tag = tp;
this.ActiveMdiChild.FormClosed += new FormClosedEventHandler(ActiveMdiChild_FormClosed);
}

tabForms.SelectedTab = (this.ActiveMdiChild.Tag as TabPage);
if (!tabForms.Visible)
tabForms.Visible = true;
}
}

// If child form closed, remove tabPage
void ActiveMdiChild_FormClosed(object sender, FormClosedEventArgs e)
{
((sender as Form).Tag as TabPage).Dispose();
}

Big Grin Big Grin Big Grin Big Grin

-----------------
 Serdar YILMAZ
Senior Developer

GeneralRe: More simple solution and support all child forms
dfhgesart
8:35 10 Feb '07  
Your solution is the correct one. The code presented in this article is too complex and not practical.

Could you submit your solution as an article with project code. It would be much easier to find and to use.
GeneralRe: More simple solution and support all child forms
pbnec
23:04 28 Oct '08  
See here~
http://www.codeproject.com/KB/cs/TabbedMDIChildForms.aspx[^]
GeneralMultiple Child Forms
rickst13
13:56 17 Dec '06  
Think you for posting this. I have a question though.

How would I use this with different types of child forms?

For example, If I wanted to have 1 tab for CarForm and 1 tab for AirplaneForm, how would I go about doing this?

Thank you.


GeneralRe: Multiple Child Forms
A55imilate
22:26 2 Jan '07  
You need to create 2 mdichildren forms CarForm.cs and Airplane.cs. If you look at the original code each the MDIChild has some functions in it for the handling of the tabs. Copy these functions to all of your MDIChildren.

public CarForm()
{
InitializeComponent();
this.Closing += new System.ComponentModel.CancelEventHandler(this.MDIChild_Closing);
this.Activated += new System.EventHandler(this.MDIChild_Activated);
}
#region tabcontrol
private TabControl tabCtrl;
private TabPage tabPag;

public TabPage TabPag
{
get {
return tabPag;
}
set {
tabPag = value;
}
}

public TabControl TabCtrl
{
set {
tabCtrl = value;
}
}
private void MDIChild_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
//Destroy the corresponding Tabpage when closing MDI child form
this.tabPag.Dispose();

//If no Tabpage left
if (!tabCtrl.HasChildren)
{
tabCtrl.Visible = false;
}
}

private void MDIChild_Activated(object sender, System.EventArgs e)
{
//Activate the corresponding Tabpage
tabCtrl.SelectedTab = tabPag;

if (!tabCtrl.Visible)
{
tabCtrl.Visible = true;
}
}
#endregion

now you need to alter the tabControl1_SelectedIndexChanged event in the MDIParent form.

private void tabControl1_SelectedIndexChanged(object sender, System.EventArgs e)
{
try {
foreach (Form childfrm in this.MdiChildren)
switch (childfrm.Tag.ToString())
{
case "0":
{
CarForm childForm = (CarForm)childfrm;
if (childForm.TabPag.Equals(tabControl1.SelectedTab))
{
//Activate the MDI child form
childForm.Select();
}
break;
}
case "1":
{
Airplane childForm = (Airplane)childfrm;
if (childForm.TabPag.Equals(tabControl1.SelectedTab))
{
//Activate the MDI child form
childForm.Select();

}
break;
}
}
}
catch {
}



Now set the tag property for each child form so the tabControl1_SelectedIndexChanged knows what type of MDIChild it is trying to set the focus on. In the example above the CarForm is 0 and Airplane is 1.

Now you can add as many different types of children as you like.

GeneralNeeds an Open File section [modified]
ArchKaine
4:03 22 Aug '06  
Hiyas,

I've been trying to implement your code into an editor I've been working on for a while, but I'm not sure how to "plug it in' to the child document to allow me to open a file and create a new tab from that.

The project is already MDI, I'm just wondering how to get the above implemented. If needed, I can supply the source, so that you can look at it. All I ask is that you try not to laugh too hard, because I'm still something of a newbie at this whole coding thing Wink It's ugly code, but works, for the most part (except when I can't figure out how to get one part of a package implemented.)

I have a vague notion on how to get it going, but I'm not sure. My file open code is functional and stable, so I'm not wanting to break it until I know I can implement this.

Anyway, thanks in advance for any help or insight that you can offer.

Here's an example of my File Open code, just so that you have something from which to work, if you like.

ArchKaine


		public void Open(string FileNameAndPath)
{
FLConfig fc = new FLConfig();
if (Path.GetExtension(FileNameAndPath).IndexOf("rtf") >= 1 && (fc.RTFSaveToggle.Checked)) {
searchableRichTextBox1.LoadFile(FileNameAndPath);
}
else if (Path.GetExtension(FileNameAndPath).IndexOf("fl") >= 1 && (fc.SaveGameToggle.Checked))
{
SavedGame sg = new SavedGame();
searchableRichTextBox1.Text = sg.DecodeCharacter(FileNameAndPath);
}
else if (Path.GetExtension(FileNameAndPath).IndexOf("ini") >= 1 && (fc.IniChunkToggle.Checked))
{
IniChunker ic = new IniChunker();
searchableRichTextBox1.Text = ic.TokenQueue.Peek().ToString();
}
else {
searchableRichTextBox1.LoadFile(FileNameAndPath, RichTextBoxStreamType.PlainText);
}
this.Text = Path.GetFileName(FileNameAndPath);
DocumentFileName = FileNameAndPath;
statusBarPanel1.Text = ("Path & File Name: " + FileNameAndPath.ToString() + ".");
statusBarPanel2.Text = ("Document Size(bytes): " + searchableRichTextBox1.TextLength.ToString());
searchableRichTextBox1.Modified = false;
}



-- modified at 9:29 Tuesday 22nd August, 2006

Some say that ignorance is bliss... Blissful, aren't they?

GeneralRe: Needs an Open File section
ArchKaine
8:12 22 Aug '06  
Hello again,

I fiddled around for a while and got everything working beautifully, thanks for the killer code Smile

ArchKaine

Some say that ignorance is bliss... Blissful, aren't they?

GeneralCustomising the tab pages
Wardy0123456789
2:59 8 Mar '06  
This is near on exactly the sorta thing im doing at the moment for a cummunity project with a few friends.

this application will have menus for showing functions like chat internet and file sharing with each function starting a new tab and each say chat window being a MDI child from the tab that its to do with.

the trouble is not so much getting this far but adding a close button like visual studio has where i can hit this and drop a tab and all its contained windows.

how do i add and use the close button for the tab control ?

good example so far though, my code is pretty much identicle to this so its good to know others thing along the same lines as me.

Im faking it ...
i dont really understand !
GeneralRe: Customising the tab pages
Wardy0123456789
8:39 8 Mar '06  
its ok i sorted that.

im now trying to get the application to support plugins using an interface i am loading an indeterminate number of plugin files in the applications plugin folder.

each plugin would in its own right be an application that im making a child of my application.

i add the plugin name to the menu in my mdi parent then when the user hits the plugin name from the menu a new tab page is created and the plugins main form is loaded in to the tab page then the user can switch between tabs / plugins at will.

thats the idea in theory ... but since theres no way to dump a form on to a tab page i just give impression thats whats going on !

i build a collection of each plugins forms and then hide forms that are not relevant to the currently selected tab page ...

i resize the tab control to show only the tabs then use show / hide to get the forms acting like parts of the tab pages they are collection members of.

is this making any sence ?

im lost in half of this but i seem to have a partially working app.

Im faking it ...
i dont really understand !
GeneralRe: Customising the tab pages
Fabian Tang
0:16 12 Mar '06  
you wrote
"i build a collection of each plugins forms and then hide forms that are not relevant to the currently selected tab page ..."

are you trying to say that each tab page inherits all the plugins, but certain plugins are only shown in certain child mdi form?

you need to modify the code so that the application can keep track of each unique child form. In the child form, assign a public unique identifier variable so that when you know what to do when you activate, deactivate or close it
GeneralChild form blinks
V1taly
4:09 28 Feb '06  
I have made similar application, but using toolbars. There is a problem with it that I haven't solved yet. If you put some contols to a maximized child form (datagrid for example) you see that when you call childForm.Select() (as well as Activate(), Focus(), BringToFront(), etc.) method form decreases to its normal size and than increases again to maximized state. It looks not very good.

P.S.
Sorry for my bad english
GeneralRe: Child form blinks
the pink jedi
18:22 2 Mar '06  
hmm....
can you give us some code?
nobody's going to understand where the real problem lies if you never supply any code
GeneralRe: Child form blinks
V1taly
21:17 2 Mar '06  
You can download source from this article, and modify constructor of MDIChild form this way
public MDIChild()
{
// // Required for Windows Form Designer support
// InitializeComponent();

// // TODO: Add any constructor code after InitializeComponent call
// DataGrid dg = new DataGrid();
dg.Dock = DockStyle.Fill;
Controls.Add(dg);
}
Then run the application open several mdichild forms, and maximize them. Click on the tab and you will see where the real problem lies.
I suppose the problem is inside CLR. A private method UpdateWindowState() of the Form class sets WindowState of a form to FormWindowState.Normal and then to FormWindowState.Maximized again. I use framework 1.1 sp1

Yesterday I found the solution, but it's not very beautiful, and works slower then ctrl-tab

[DllImport("User32.dll")]
public static extern bool LockWindowUpdate(IntPtr hWnd);

private void tabControl1_SelectedIndexChanged(object sender, System.EventArgs e)
{
foreach (MDIChild childForm in this.MdiChildren)
{
//Check for its corresponding MDI child form
if (childForm.TabPag.Equals(tabControl1.SelectedTab))
{
LockWindowUpdate( childForm.Handle );
//Activate the MDI child form
childForm.Select();
LockWindowUpdate( IntPtr.Zero );
return;
}
}
}


-- modified at 2:24 Friday 3rd March, 2006
GeneralRe: Child form blinks
Fabian Tang
0:47 12 Mar '06  
thr culprit lies in the fact that childForm.WindowState is normal before the statement "childForm.Select();" and becomes maximized straight after the statement.
That is why you see that flicker.
I think the problem lies with microsoft on the way they design this interface.
GeneralRe: Child form blinks
tomek13m
3:35 18 Sep '06  
I got the same flicker problem.
Open and convert the demo project in visual studio 2005. Compile and run, you'll get the flicker when the windows are maximized...
Tried the API method but it didn't workFrown
GeneralRe: Child form blinks
Serdar YILMAZ
22:47 26 Jan '07  
Hi,
Set child form with = 0; or left = -1000;

-----------------
 Serdar YILMAZ
Senior Developer

GeneralRe: Child form blinks
Member 1148465
14:53 30 Jun '09  
I am getting the same problem. Could please provide more details on the solution?

Thanks.
Questionused this approach for a customized browser
Mike Porco
15:16 18 Jan '06  
it works well but I am having a problem accessing the webbrowser control in the child windows properties. I keep getting a null exception. Do you have any suggestions.

I'm currently trying:

Dim childForm As New Form
Url = childForm.WebBrowser1.Url.ToString


but the url value seems to be null.
Thanks for any help you can provide.
AnswerRe: used this approach for a customized browser
Fabian Tang
7:14 22 Jan '06  
you can use
childForm.axWebBrowser1.LocationURL

it is null before the browser detects the page
you should be able to get the string once the page has been loaded. Take note that this string is the absolute URL of the page.
QuestionGood, but what else
Shashidharreddy
18:26 27 Dec '05  
that's a great idea, but how does it be more effictive, as there are many tools available which is already doing this job as Crazy browser and few more
as u specified. How it could be used more effective.

Shashidhar.


Last Updated 22 Dec 2005 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010