Team LiB
Previous Section Next Section

The Multiple-Document Interface

When you think about it, the SDI as I have shown it here is actually a misnomer. It does, after all, show multiple documents. It just does not show them in a cohesive manner like the MDI interface does.

So what is an MDI program, anyway? An MDI application has a form that acts as a container for any child forms that belong to it. Word 97 is a true MDI application. Excel is also a true MDI application. Figure 3-5 shows you the SDI project you just completed reformulated as an MDI application.

Click To expand
Figure 3-5: The MDI form of the SDI project

It is actually quite easy to convert the SDI application to an MDI application, and I show you how to do so in this section. Once you have finished with the code, you will see that the .NET Framework supports many nice features of MDI applications that you would normally have to program yourself in an SDI environment.

Start a new C# or VB project. Mine is called "MDIapp." While you have this new project open, start up the SDI project you just finished in a different window. You will need to complete the following steps to generate this project:

  1. Size the existing form to be 800×600. Name it UberForm and change its text to read HR Program.

  2. Make the form start up in the center of the screen.

  3. Change the IsMdiContainer property to true.

  4. Copy and paste the MainMenu control from the SDI project to the form on this project. (I love how copy and paste works between .NET projects.)

  5. Delete the separator bar from the Window menu choices in the main menu (under the Close All choice).

  6. In the Property window for the Window choice, change the MdiList property to true.

  7. Add Tile Horizontally to the Window menu and name it mnuHoriz.

  8. Add Tile Vertically to the Window menu and name it mnuVert.

  9. Add Cascade to the Window menu and name it mnuCascade.

  10. Copy and paste the status bar from the SDI project to the main form on this project.

  11. Create a new form called Employee.

  12. Copy and paste the controls from the Employee form in the SDI application to this Employee form.

  13. Create a new form called Payroll.

  14. Create a new form called Training.

  15. Create a new form called Scheduling.

  16. Add a label on the Payroll form called lblCash. Put a dollar sign ($) in for the Text property. Center the text and set the font at 100 points.

This is it for the visible part of the MDI application. You can now close the SDI project. Listings 3-2a and 3-2b show the code for the MDI application's main form.

Listing 3-2a: C# Code for the MDI Application
Start example

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace MDIapp_c {
  /// <summary>
  /// Summary description for Form1.
  /// </summary>
  public class UberForm : System.Windows.Forms.Form
  {
    private System.Windows.Forms.MainMenu mainMenu1;
    private System.Windows.Forms.MenuItem mnuFile;
    private System.Windows.Forms.MenuItem mnuClose;
    private System.Windows.Forms.MenuItem mnuEdit;
    private System.Windows.Forms.MenuItem mnuEmp;
    private System.Windows.Forms.MenuItem mnuTrain;
    private System.Windows.Forms.MenuItem mnuPayroll;
    private System.Windows.Forms.MenuItem mnuSked;
    private System.Windows.Forms.MenuItem mnuWindow;
    private System.Windows.Forms.MenuItem mnuHelp;
    private System.Windows.Forms.StatusBar statusBar1;
    private System.Windows.Forms.StatusBarPanel statusBarPanel1;
    private System.Windows.Forms.StatusBarPanel statusBarPanel2;
    private System.Windows.Forms.StatusBarPanel statusBarPanel3;
    private System.ComponentModel.Container components = null;
    private System.Windows.Forms.MenuItem mnuHoriz;
    private System.Windows.Forms.MenuItem mnuVert;
    private System.Windows.Forms.MenuItem mnuCascade;
    private System.Windows.Forms.MenuItem mnuCloseAll;

    #region Class Local Variables

    Payroll    PayForm;
    Employee   EmpForm;
    Scheduling SkedForm;
    Training   TrainForm;

    #endregion
    public UberForm()
    {
      InitializeComponent();

      this.Menu = mainMenu1;
      mnuClose.Click    += new EventHandler(this.CloseMe);
      mnuEmp.Click      += new EventHandler(this.OpenWindow);
      mnuSked.Click     += new EventHandler(this.OpenWindow);
      mnuPayroll.Click  += new EventHandler(this.OpenWindow);
      mnuTrain.Click    += new EventHandler(this.OpenWindow);
      mnuCloseAll.Click += new EventHandler(this.CloseAllWindows);

      mnuHoriz.Click    += new EventHandler(this.ArrangeWindow);
      mnuVert.Click     += new EventHandler(this.ArrangeWindow);
      mnuCascade.Click  += new EventHandler(this.ArrangeWindow);
    }

    protected override void Dispose( bool disposing )
    {
      if( disposing )
      {
        if (components != null)
        {
          components.Dispose();
        }
      }
      base.Dispose( disposing );
    }

    #region Windows Form Designer generated code
...
...
...
    #endregion

    [STAThread]
    static void Main()
    {
      Application.Run(new UberForm());
    }
    private void UberForm_Load(object sender, System.EventArgs e)
    {
    }

    #region events

    private void CloseMe(object sender, EventArgs e)
    {
      this.Close();
    }

    private void OpenWindow(object sender, EventArgs e)
    {
      MenuItem m;

      if(sender is MenuItem)
        m = (MenuItem)sender;
    else
        return;

    if(m == mnuEmp)
    {
      if(EmpForm == null)
      {
        EmpForm = new Employee();
        EmpForm.MdiParent = this;
        EmpForm.Disposed += new EventHandler(this.ByByWindow);
        EmpForm.Show();
      }
      else
        EmpForm.Focus();
    }

    if(m == mnuTrain)
    {
      if(TrainForm == null)
      {
        TrainForm = new Training();
        TrainForm.MdiParent = this;
        TrainForm.Disposed += new EventHandler(this.ByByWindow);
        TrainForm.Show();
      }
      else
        TrainForm.Focus();
    }

    if(m == mnuPayroll)
    {
      if(PayForm == null)
      {
        PayForm = new Payroll();
        PayForm.MdiParent = this;
        PayForm.Disposed += new EventHandler(this.ByByWindow);
        PayForm.Show();
      }
      else
        PayForm.Focus();
    }

    if(m == mnuSked)
    {
      if(SkedForm == null)
      {
        SkedForm = new Scheduling();
        SkedForm.MdiParent = this;
        SkedForm.Disposed += new EventHandler(this.ByByWindow);
        SkedForm.Show();
      }
      else
        SkedForm.Focus();
    }
  }

  private void CloseAllWindows(object sender, EventArgs e)
  {
    if(EmpForm != null)
      EmpForm.Dispose();
    if(PayForm != null)
      PayForm.Dispose();
    if(TrainForm != null)
      TrainForm.Dispose();
    if(SkedForm != null)
      SkedForm.Dispose();
  }

    private void ByByWindow(object sender, EventArgs e)
    {

      if(sender == EmpForm)
        EmpForm = null;
      if(sender == PayForm)
        PayForm = null;
      if(sender == TrainForm)
        TrainForm = null;
      if(sender == SkedForm)
        SkedForm = null;
    }

    private void ArrangeWindow(object sender, EventArgs e)
    {
      MenuItem m;

      if(sender is MenuItem)
        m = (MenuItem)sender;
      else
        return;

      if(m == mnuHoriz)
        this.LayoutMdi(MdiLayout.TileHorizontal);
      if(m == mnuVert)
        this.LayoutMdi(MdiLayout.TileVertical);
      if(m == mnuCascade)
        this.LayoutMdi(MdiLayout.Cascade);
    }

    #endregion
  }
}
End example
Listing 3-2b: VB Code for the MDI Application
Start example

Public Class UberForm
  Inherits System.Windows.Forms.Form

#Region "Class Local Variables"

  Dim PayForm As Payroll
  Dim EmpForm As Employee
  Dim SkedForm As Scheduling
  Dim TrainForm As Training

#End Region

#Region " Windows Form Designer generated code "

  Public Sub New()
    MyBase.New()

    'This call is required by the Windows Form Designer.
    InitializeComponent()

    Me.Menu = mainMenu1
    AddHandler mnuClose.Click, New EventHandler(AddressOf Me.CloseMe)
    AddHandler mnuEmp.Click, New EventHandler(AddressOf Me.OpenWindow)
    AddHandler mnuSked.Click, New EventHandler(AddressOf Me.OpenWindow)
    AddHandler mnuPayroll.Click, New EventHandler(AddressOf Me.OpenWindow)
    AddHandler mnuTrain.Click, New EventHandler(AddressOf Me.OpenWindow)
    AddHandler mnuCloseAll.Click, New EventHandler(AddressOf Me.CloseAllWindows)

    AddHandler mnuHoriz.Click, New EventHandler(AddressOf Me.ArrangeWindow)
    AddHandler mnuVert.Click, New EventHandler(AddressOf Me.ArrangeWindow)
    AddHandler mnuCascade.Click, New EventHandler(AddressOf Me.ArrangeWindow)

  End Sub

...
...
...
#End Region

  Private Sub UberForm_Load(ByVal sender As System.Object, _
                            ByVal e As System.EventArgs) Handles MyBase.Load
  End Sub

#Region "Events"

  Private Sub CloseMe(ByVal sender As Object, ByVal e As EventArgs)
    Me.Close()
  End Sub

  Private Sub OpenWindow(ByVal sender As Object, ByVal e As EventArgs)
    Dim m As MenuItem

    If sender.GetType() Is GetType(MenuItem) Then
      m = CType(sender, MenuItem)
    Else
      Return
    End If

    If m Is mnuEmp Then
      If EmpForm Is Nothing Then
        EmpForm = New Employee()
        AddHandler EmpForm.Disposed, AddressOf Me.ByByWindow
        EmpForm.MdiParent = Me
        EmpForm.Show()
      Else
        EmpForm.Focus()
      End If
    End If

    If m Is mnuTrain Then
      If TrainForm Is Nothing Then
        TrainForm = New Training()
        AddHandler TrainForm.Disposed, AddressOf Me.ByByWindow
        TrainForm.MdiParent = Me
        TrainForm.Show()
      Else
        TrainForm.Focus()
      End If
    End If

    If m Is mnuPayroll Then
      If PayForm Is Nothing Then
        PayForm = New Payroll()
        AddHandler PayForm.Disposed, AddressOf Me.ByByWindow
        PayForm.MdiParent = Me
        PayForm.Show()
        Else
          PayForm.Focus()
        End If
      End If

      If m Is mnuSked Then
        If SkedForm Is Nothing Then
          SkedForm = New Scheduling()
          AddHandler SkedForm.Disposed, AddressOf Me.ByByWindow
          SkedForm.MdiParent = Me
          SkedForm.Show()
        Else
          SkedForm.Focus()
        End If
      End If

    End Sub

    Private Sub ArrangeWindow(ByVal sender As Object, ByVal e As EventArgs)
      Dim m As MenuItem

    If sender.GetType() Is GetType(MenuItem) Then
      m = CType(sender, MenuItem)
    Else
      Return
    End If

    If m Is mnuHoriz Then
      Me.LayoutMdi(MdiLayout.TileHorizontal)
    End If

    If m Is mnuVert Then
      Me.LayoutMdi(MdiLayout.TileVertical)
    End If

    If m Is mnuCascade Then
      Me.LayoutMdi(MdiLayout.Cascade)
    End If

  End Sub

  Private Sub CloseAllWindows(ByVal sender As Object, ByVal e As EventArgs)
    If Not EmpForm Is Nothing Then
      EmpForm.Dispose()
    End If
    If Not PayForm Is Nothing Then
      PayForm.Dispose()
    End If
    If Not TrainForm Is Nothing Then
      TrainForm.Dispose()
    End If
    If Not SkedForm Is Nothing Then
      SkedForm.Dispose()
    End If
  End Sub

  Private Sub ByByWindow(ByVal sender As Object, ByVal e As EventArgs)

    If sender Is EmpForm Then
      EmpForm = Nothing
    End If
    If sender Is PayForm Then
      PayForm = Nothing
    End If
    If sender Is TrainForm Then
      TrainForm = Nothing
    End If
    If sender Is SkedForm Then
      SkedForm = Nothing
    End If
  End Sub
#End Region
End Class
End example

There is not anywhere near as much to this code. I do not have to keep track of the windows for listing purposes anymore. The .NET Framework does that by using just one property in the menu. I had to capture and dissect all kinds of events in the SDI project to accomplish the same thing.

Notice that when I instantiate each form, I make its MdiParent equal to the main form. This is all I need to do to make a form a child. Leave this line of code out and your child form will be an SDI. This is a great enhancement over VB 6.0, where you had to change the form's property at design time to go from being an MDI child to not. It makes it hard to reuse the same form in two projects both ways.

If you think about it, there is not much you have to do to add a menu option to make this project an SDI or an MDI on the fly. You can do all the rearranging in code. As a matter of fact, you can copy the SDI project's main form code over to this one and do just that if you like. Let me know how you get on, OK?


Team LiB
Previous Section Next Section