In This Article

Working with MDI

The bar controls have several great features for working with MDI:

  • Standard MDI button control
  • Flexible command link merging
  • MDI window lists via expanders

Standard MDI Button Control

When standard MDI is used in an application and a child MDI window is maximized, its system button and other buttons (minimize, restore, and close) are typically added to the main menu. The bar controls will handle this situation and will place the appropriate buttons in the MenuBar if each button is allowed to be visible.

Screenshot

This table indicates the members of BarManager that control standard MDI button visibility:

Member Description
MdiChildCloseButtonVisible Property Gets or sets whether maximized MDI child windows (in standard MDI mode) display a close button on the menubar.
MdiChildMinimizeButtonVisible Property Gets or sets whether maximized MDI child windows (in standard MDI mode) display a minimize button on the menubar.
MdiChildRestoreButtonVisible Property Gets or sets whether maximized MDI child windows (in standard MDI mode) display a restore button on the menubar.
MdiChildSystemButtonVisible Property Gets or sets whether maximized MDI child windows (in standard MDI mode) display a system button on the menubar. The system button, when clicked, displays a system menu for the MDI child window.

The bar controls support the merging of command links from two different bar controls, often referred to as MDI merging. However since dockable toolbars (and menubars) are lightweight elements and do not inherit from Control, the bar controls can't automatically merge a menubar from a child MDI windows with a menubar from a parent MDI window. This is easily done in code though with a few lines.

This table indicates the static members of BarManager that control merging:

Member Description
Merge Method Merges the source IBarControl with a target IBarControl.
RevertAllMerges Method Reverts any existing merges on the target IBarControl.
RevertMerge Method Reverts the merge from the source IBarControl on the target IBarControl.

This first example is useful only if standard MDI is used. It overrides the OnMdiChildActivate method of the parent MDI window to add the merge code. Assume that both the parent MDI window and the child MDI window have their own BarManager, each with a MenuBar defined. Also assume that the child MDI window is a custom type BarMdiMergeChildForm and that type has a MenuBar property exposed that provides direct access to the child MDI window's MenuBar.

/// <summary>
/// Raises the <c>MdiChildActivate</c> event.
/// </summary>
/// <param name="e">Event arguments.</param>
protected override void OnMdiChildActivate(EventArgs e) {
	// Call the base method.
	base.OnMdiChildActivate(e);

	// Merge or revert merge
	if (this.ActiveMdiChild is BarMdiMergeChildForm) {
		BarMdiMergeChildForm childForm = (BarMdiMergeChildForm)this.ActiveMdiChild;
		BarManager.Merge(childForm.MenuBar, barManager.MenuBar, true);
	}
	else
		BarManager.RevertAllMerges(barManager.MenuBar);
}

This second example is useful only if Actipro Docking & MDI controls are being used for MDI. It handles the SelectedDocumentChanged event of the DockManager and performs the merge there. Assume that both the parent Form and the document window have their own BarManager, each with a MenuBar defined. Also assume that the document window is a custom type MdiMergeDocumentWindow and that type has a MenuBar property exposed that provides direct access to the document window's MenuBar.

/// <summary>
/// Occurs when the selected document is changed.
/// </summary>
/// <param name="sender">Sender of the event.</param>
/// <param name="e">Event arguments.</param>
protected override void dockManager_SelectedDocumentChanged(object sender, EventArgs e) {
	// Merge or revert merge
	if (dockManager.SelectedDocument is MdiMergeDocumentWindow) {
		MdiMergeDocumentWindow documentWindow = (MdiMergeDocumentWindow)dockManager.SelectedDocument;
		BarManager.Merge(documentWindow.MenuBar, barManager.MenuBar, true);
	}
	else
		BarManager.RevertAllMerges(barManager.MenuBar);
}

Each command link has a couple properties that govern how it is merged with another bar control.

The MergeAction is the primary controller for how merging occurs. It is of the enumeration type BarMergeAction, which has these values:

Value Description
Append Appends the command link to the end of the target command links collection.
Insert Inserts the command link before the matched command link.
InsertAfter Inserts the command link after the matched command link.
MatchOnly A match is required, but no action is taken. Use this for tree creation and successful access to nested layouts.
Remove If the command link is on the source, the matched command link on the target is removed and the source command link is not merged. If the command link is on the target, the command link is removed.
Replace Replaces the matched command link with the source command link. The original command link's drop-down command links do not become children of the incoming command link.

"Matching" of command links is done by comparing each command link's merge key. The resolved merge key defaults to the command's full name, unless the MergeKey property overrides it. If the command link is a merge source command link, the resolved merge key looks for a match on the target command link collection. If the command link is a merge target command link, the resolved merge key is used for matching against source command links.

Therefore if you wished to insert a File.Save source command link before a File.Exit target command link, you'd set the source command link's MergeAction property to BarMergeAction.Insert and the source command link's MergeKey property to File.Exit.

MDI Window List

The BarExpanderButtonCommand is capable of dynamically populating child command links. One of the built-in automatic population styles is BarExpanderButtonCommandPopulationStyle.StandardMdiWindowList. This value can be set to the PopulationStyle property. When set, the expander will automatically list any standard MDI windows in the Form containing the host container control. Note that this only works for standard MDI mode.

Since tabbed MDI (an advanced option provided by our Docking & MDI controls) does not have native support in Windows Forms, listing MDI windows in that mode is a little more complex, but can still be done using expanders. Leave the population style of the expander as BarExpanderButtonCommandPopulationStyle.Custom and handle the CommandPopup event. This event is raised for expanders whenever they are clicked (on a toolbar) or before they are displayed (on a menu), allowing you to update the child command links.

In that event you simply clear any existing child command links, and add one command link for each TabbedMdiWindow in the DockManager. Set the reference to the TabbedMdiWindow in the Tag property of each command link. This code illustrates how to implement this feature and even shows asterisks for modified documents from within the event handler:

switch (e.Command.FullName) {
	case "Window.WindowList": {
		// Populate the command with the list of open windows
		BarExpanderButtonCommand command = (BarExpanderButtonCommand)e.Command;
		command.CommandLinks.Clear();
		foreach (TabbedMdiWindow tabbedMdiWindow in dockManager.ActiveDocuments) {
			string text = tabbedMdiWindow.Text;
			DocumentWindow documentWindow = tabbedMdiWindow as DocumentWindow;
			if (documentWindow != null)
				text = documentWindow.FileName + (documentWindow.Modified ? "*" : String.Empty);
			BarButtonLink commandLink = new BarButtonLink("WindowActivate", String.Empty, text,
				tabbedMdiWindow.ImageIndex, true, true, (dockManager.SelectedDocument == tabbedMdiWindow), false);
			commandLink.Command.Tag = tabbedMdiWindow;
			command.CommandLinks.Add(commandLink);
		}
		break;
	}
}

Then the next step is to handle the CommandClick event to process the window activation. This code shows how to activate a TabbedMdiWindow from within the event handler:

if (e.Command.Category == "WindowActivate") {
	// Activate the TabbedMdiWindow in the Tag
	((TabbedMdiWindow)e.Command.Tag).Activate();
	return;
}

After implementing those events, both standard and tabbed MDI are supported in a window list expander item when using a DockManager.