Creating Tabbed MDI Form
A tutorial for creating a tabbed MDI form
Introduction
This is a tutorial for creating a tabbed MDI form. With this step, you'll know how easy it is to create a tabbed MDI form.
Background
When I was trying to make a text editor, I found this trick.
Using the Code
I create a second form called frmChild
. This is the template form for MDI child. But first, create a Parent
form which has: tab container, menu / button to add and delete, menu to browse the tabs. To set Parent
form as MDI parent
, in properties window, set isMDIContainer = true
. You may add menu to list your MDI child, but this is for checking for your MDI children, are they synchronized with tabs or not. Don't forget to set the control of the child form as public
if you want that the control can be accessed from the Parent
form. Open frmChild.Designer.cs, navigate below "Windows Form Designer generated code" region. You will see something like this:
private System.Windows.Forms.RichTextBox richTextBox1;
Change the line like this:
public System.Windows.Forms.RichTextBox richTextBox1;
That's it! From this example, now you can access richtextbox
from the Parent
form. From the add menu click event, suppose it's called mnuAdd_Click
, add new child form and tab, also tab list menu:
private void mnuAdd_Click(object sender, EventArgs e)
{
frmChild newChild = new frmChild(); //add new child
TabPage childTab = new TabPage(); //create new tab page
newChild.MdiParent = this; //set as child of this form
newChild.Name = "Child" + createdTab.ToString();
newChild.Text = " Child no " + createdTab.ToString();
childTab.Name = newChild.Name;
//make sure name and text are same
childTab.Text = newChild.Text;
//this is for synchronize later
tabControl1.TabPages.Add(childTab); //add new tab
newChild.richTextBox1.Parent = childTab; //attach to tab
ToolStripMenuItem newMenuTab = new ToolStripMenuItem();
//create menu to hold tab
newMenuTab.Text = newChild.Text;
//make sure the name and text are same to synchronize later
newMenuTab.Name = newChild.Name;
mnuTab.DropDownItems.Add(newMenuTab); //add menu item
newMenuTab.Click += new EventHandler(newMenuTab_Click);
//add event handler
tabControl1.SelectTab(childTab);
//this is to make sure that tab page is selected in the same time
newChild.Show();
//as new form created so that corresponding tab and child form is active
createdTab++; //increment of course
}
When tab list menu is clicked, you select one tab, you want the corresponding Child
form to be activated too.
void newMenuTab_Click(object sender, EventArgs e)
{
foreach (TabPage theTab in tabControl1.TabPages)
{
if (theTab.Text == sender.ToString ()) //sender is the clicked menu
{ /*when menu is clicked, activate the corresponding form and tab page*/
tabControl1.SelectTab(theTab); /* when menu is clicked, select
tab and activate MDI child*/
foreach (Form WantToSelect in this.MdiChildren)
{
if (WantToSelect.Name == theTab.Name) /*this is why you must
make sure child form's and tab page's name are same for easier control*/
{
WantToSelect.Select(); //activate MDI child
}
}
}
}
}
of course, you want the corresponding mdiChild
to be selected when you clicked the tab.
private void tabControl1_Selected(object sender, TabControlEventArgs e)
{
foreach (frmChild WantToSelect in this.MdiChildren )
{
if (tabControl1.SelectedTab != null) /*if no child has created, an error
will occur */
{
if (WantToSelect.Name == tabControl1.SelectedTab.Name) /*again, this
is why you must make sure child form's and tab page's name are same for
easier control*/
{ //
WantToSelect.Select(); //activate MDI child
}
}
}
}
The corresponding mdiChild
must close when the tab is closed. Suppose the close menu is called mnuClose_Click
.
private void mnuClose_Click(object sender, EventArgs e)
{
mnuTab.DropDownItems.RemoveByKey(tabControl1.SelectedTab.Name);
//this is why you must make sure menu's and tab page's name are same
this.ActiveMdiChild.Close();
//because of synchronize routine, you must close the form first before tab.
tabControl1.SelectedTab.Dispose();
//if tab first, activated tab will change and so the child form,
//this will be the closed form. The wrong form will close....
}
The last thing is the importance of activating the corresponding tab with the Child
form. For example, accessing richtextbox
properties.
private void lblChar_Click(object sender, EventArgs e)
{
frmChild childForm = (frmChild ) this.ActiveMdiChild ; //this is the reason
//why synchronization between tab and active MDI child is important
lblChar.Text = "Char : " + childForm.richTextBox1.TextLength.ToString();
}
Points of Interest
That's just the sample code, actually, I'm not using RichTextBox
for my text editor. Instead, I'm using scintilla net wrapper.
History
- 31st October, 2008: Initial post