Multiple Document Interface


Just as controls can be grouped into containers, windows themselves can be grouped into containers in a style of application called Multiple Document Interface (MDI). MDI was invented as a way to contain a set of related windows in a single frame, as shown in Figure 2.31.

Figure 2.31. Sample MDI Form

An MDI form has two pieces: a parent and a child. You designate the parent form by setting the IsMdiContainer property to true, and you designate the child form by setting the MdiParent property before showing the form:

 void InitializeComponent() {   ...  this.IsMdiContainer = true;  ... } void cmdFileNewChild_Click(object sender, EventArgs e) {   Form child = new ChildForm();  child.MdiParent = this;  child.Show(); } 

Just as the parent has a property indicating that it's an MDI parent, the child has a property, IsMdiChild, that tells it that it's being shown as an MDI child. And just as a form is a collection of controls, an MDI parent form has a collection of MDI children called MdiChildren. When a child is activated, either by direct user input or by the Activate method, the MDI parent receives the MdiChildActivate event. To see or change which of the MDI children is currently active, each MDI parent form provides an ActiveMdiChild property.

An MDI parent is expected to have two sets of special menu items: one to arrange the children inside the parent frame, and a second one to list the active children and select among them. Figure 2.32 shows a typical menu of this sort .

Figure 2.32. An MDI Child Management Menu

In Figure 2.32, the top-level Window menu has four items for arranging the child forms inside the MDI parent. By setting the Window menu's MdiList property to true, you display a separator and all the Text properties of all the MDI child forms at the end of the menu, allowing the user to pick one to activate. If the Window menu were empty ”for example, if you wanted to list the child windows in a submenu ”no separator would be added.

To implement the items that arrange the children inside the parent, the Form class provides the LayoutMdi method, which takes one of the four MdiLayout enumeration values:

 void windowArrangeIconsMenuItem_Click(object sender, EventArgs e) {  this.LayoutMdi(MdiLayout.ArrangeIcons);  } void windowCascadeMenuItem_Click(object sender, EventArgs e) {  this.LayoutMdi(MdiLayout.Cascade);  } void windowTileChildrenVertMenuItem_Click(object sender, EventArgs e) {  this.LayoutMdi(MdiLayout.TileVertical);  } void windowTileChildrenHorizMenuItem_Click(object sender, EventArgs e) {  this.LayoutMdi(MdiLayout.TileHorizontal);  } 

To implement the Windows cascading menu to show MDI child forms and have the selected child brought to the front, you set the Windows menu item MdiList property to true.

Menu Merging

WinForms makes MDI so easy that it almost takes all the satisfaction out of things until we get to menu merging, which gives us something to sink our teeth into. The basic idea of menu merging is that there is only one main menu shown in a form, even if that form contains MDI children. Instead of letting each MDI child have its own menu, you merge the menu items of the child with the menu items of the parent, simplifying things for the user.

Why don't you simply put everything into the parent's main menu to start with? The reason is that lots of menu items, such as File Close, don't make sense without a child, so showing them isn't helpful. Similarly, the set of operations can well change between MDI children, so the merged menu should consist only of the items from the parent that always make sense, such as File Exit, and the items from the currently active child.

For example, Figure 2.33 shows an MDI parent File menu when there are no children, and Figure 2.34 shows the same File menu when there is a child.

Figure 2.33. MDI Parent File Menu with No MDI Children

Figure 2.34. MDI Parent File Menu with an MDI Child

In the Designer, both the parent and the child forms have a main menu, as shown in Figure 2.35.

Figure 2.35. The Parent and Child Menus in the Designer

Notice that the child's menu items don't contain all the items shown in Figure 2.34 when the child is active at run time. Instead, the child has only the new items that are to be added to the parent menu. For the merging to work, we need to set two properties on the menu items to be merged ”at the top level, such as File, as well as at the lower levels, such as File New.

Merging is governed on a per-item basis via MergeType and MergeOrder. The MergeType property is one of the following MenuMerge enumeration values:

 enum MenuMerge {   MergeItems,   Add,   Remove,   Replace, } 

MergeOrder dictates how things are ordered at the top level and in the submenus. The top-level menu is arranged by merge order right to left, lowest to highest. In our example, notice that the parent File and Window menus are separated by the child Edit menu. To do this, you set the merge order for File, Edit, and Window to 0, 1, and 2, respectively. But don't be confused by the numbers I used. I could have easily used 0, 100, and 404 to achieve the same menu item placement. The actual numbers don't matter ”only the order.

Because the parent as well as the child menus have a File menu at merge order 0, we have several options. One is to set the merge types to Add, giving us two File menus when a child is created. That's useful when the menus have different names , as with our Edit and Window menus, but it doesn't work when they have the same name .

Another option is to set the merge type to Remove on the parent menu, removing the parent's File menu when the child menu items are merged. Remove is handy when a menu item isn't useful after two menus are merged, but not in this case because the child needs a File menu.

A third option is to use Replace and let the child's File menu completely replace that of the parent, but this removes all the menu items owned by the parent File menu that are child-independent.

In our example, the option we want is MergeItems, which merges second-level items using the same algorithm used to merge items at the top level ”that is, as specified by the MergeOrder and MergeType properties. Tables 2.1 and 2.2 show the menu merge settings used by the example to create a merged top-level menu and a merged File menu.

If you find that you can't get the items you want in the merged menu or if you have dynamic menu items, you can access the parent's menu using the parent's public MergedMenu property. In this way, you can either modify WinForms' automatic action, or you can replace it with something of your own making.

And as if that weren't enough, because you can still put controls on an MDI parent form, you can actually mix docking with MDI to achieve layouts such as the one shown in Figure 2.36.

Figure 2.36. Mixing Docking and MDI

Notice that the MDI children automatically arrange themselves in the client area not occupied with docked controls, making these kinds of layouts possible.



Windows Forms Programming in C#
Windows Forms Programming in C#
ISBN: 0321116208
EAN: 2147483647
Year: 2003
Pages: 136
Authors: Chris Sells

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net