Windows Forms: Applications / Page 4


[previous] [next]

Windows Forms: Applications [con't]

Multiple-SDI Applications

A multiple-SDI application has multiple windows for content, although each window is a top-level window. Internet Explorer and Office 2003 are popular examples of multiple-SDI applications. Figure 14.4 shows an example of a multiple-SDI application.

A multiple-SDI application typically has the following features:

  • A single instance of the application is running.
  • Multiple top-level windows are running independently of each other.
  • It doesn't reopen files that are currently loaded.
  • When the last window goes away, the application does, too.
  • A Window menu allows a user to see and select from the currently available windows.

When a document is created or opened, it is loaded into a new window each time, whether the file was requested via the menu system or the command line. The first time the application is called, the first new instance of the top-level form is created and set as the main application form instance; if a file was requested, it is also opened by the form.

Subsequent requests to the application are routed to the custom WindowsForms-ApplicationBase object located in the already-running application instance. Each request is handled to create a new form and build up the appropriate menu structures to support navigation between top-level instances, as well as opening and closing existing top-level instances. Figure 14.5 illustrates the work flow.

Multiple SDI requires single-instance support, which we acquire by deriving from WindowsFormsApplicationBase, as you saw earlier. We also need to ensure that the application stops running only after all top-level forms have been closed. We make the appropriate configurations from the constructor of the custom WindowsFormsApplicationBase class:

By default, the ShutdownStyle for a WindowsFormsApplicationBase object is After-MainFormCloses, which refers to the form specified as the main form. However, with a multiple-instance SDI application, no form is the main form; therefore, no matter which form was created first, we want the application to close only after the last remaining top-level form is closed, and hence the need to explicitly set ShutdownStyle to AfterAllFormsClose.

Next, MultiSDIApplication must handle the first execution of the application. It does this by overriding OnCreateMainForm to create a new TopLevelForm object:

In this code, if a file argument was passed, a request is made to the main form to open it. Because all forms in a multiple-instance SDI application are top-level, however, no form is actually the main form. However, we must specify one if we override OnCreateMainForm, which helps later when the application needs to know which of the top-level forms is the active form. OnCreateMainForm passes the command line args—supplied by WindowsFormsApplicationBase.CommandLineArgs—to the helper CreateTopLevelWindow method, which parses the args for a file name, passing whatever it finds to the static CreateTopLevelWindow method that's implemented by TopLevelForm. CreateTopLevelWindow is static because no specific form instance is responsible for creating another form.

To cope with subsequent requests to launch the application, we again override OnStartup NextInstance:

Here, the helper CreateTopLevelWindow is again passed command line arguments and called upon to create a new top-level window, opening a file if necessary.

Multiple-instance SDI applications also allow files to be opened from existing top-level forms via the File | Open menu, something we implement using the same static CreateTopLevelWindow method to open files from the command line:

CreateTopLevelWindow contains the code to check whether the desired file is already opened and, if it is, to bring the top-level window that contains it to the foreground; otherwise, the file is opened into a new top-level window.

Multiple-instance SDI applications also typically allow the creation of new files from the command line or from the File | New Window menu of a currently open top-level form. We tweak the OpenFile method to not open a file if null or if an empty string was passed as the file name:

Because a new file doesn't have a name, the top-level form gives it one; the standard naming convention for a new file is the concatenation of some default text with a version number. In this example, we use a combination of "Untitled" and an incremental count of the number of opened top-level forms, for uniqueness.

As mentioned before, a multiple-SDI application should implement a menu that allows users to navigate between open top-level forms as this is easier when files have unique names. MultiSDIApplication is an appropriate location for this logic because it manages the application:

The MultiSDIApplication class uses the AddTopLevelForm method to keep track of a list of top-level forms as they are added. Each new form is kept in a collection and is watched for Activated and FormClosed events. When a top-level form is activated, it becomes the new "main" form, which is the one whose closure is detected by the base ApplicationContext class. When a top-level form closes, it's removed from the list. If the closed form was the main form, another form is promoted to that lofty position. When the last form goes away, the base ApplicationContext class notices and exits the application.

To keep the context up-to-date with the current list of top-level forms, the custom context watches for the Closed event on all forms. In addition, the custom context needs to be notified when a new top-level form has come into existence, a task that is best handled by the new form itself:

The only remaining task is to designate and populate the Window menu with one menu item for each top-level form. The forms themselves can do this by handling the Drop-DownOpening event on the ToolStripMenuItem's Window object, using that opportunity to build the list of submenu items based on the names of all the forms. However, this code is boilerplate, so it's a good candidate to be handled by MultiSDIApplication on behalf of all top-level windows, from the AddWindowMenu method:

Each top-level form with a Window menu can add it to the context, along with itself, when it's created:

Now, when the Window menu is shown on any top-level window, the Drop-DownOpening event fires. This constructs a new menu showing the currently open top-level forms during the time gap between mouse click and menu display:

As each menu item is added to the Window menu, a handler is added to the Click event so that the appropriate form can be activated when it's selected. The form associated with the ToolStripMenuItem's Tag property is extracted and activated:

That's it. The extensible lifetime management of Windows Forms applications via a custom application context, along with a helper to find and activate application instances already running, provides all the help we need to build a multiple-SDI application in only a few lines of code. The result is shown in Figure 14.6.

Multiple-SDI applications share much in common with MDI applications, although each document in an MDI application is loaded into a child window rather than a new main window. The key similarities include the requirement for MDI applications to be managed from a single executable and the ability to handle command line parameters.


[previous] [next]