Starting a Windows Forms .NET Application

This week at work I have been redesigning the flow of our internal application. When Sally gets into work the first thing she does is launch this internal application. The application opens to a login form which disappears when she enters her credentials. A secondary screen then shows up asking which set of data she would like to work with. She chooses what she’s been assigned to work on and waits for the data to load in a third screen.

The code required to launch such an application is very straight forward. The login form needs to be displayed and when it is dismissed the secondary form can be shown. The third screen can be launched off of the second and will stay alive as long as the second is open.

Program.cs

///
/// Entry point for the test application
///
static class Program
{
    ///
    /// The main entry point for the application.
    ///
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        // Ask the user to login
        Login.LoginScreen login = new Login.LoginScreen();
        Application.Run(login);

        if (login.DialogResult == DialogResult.OK)
        {
            // Run the main application
            Application.Run(new NewWindowApp());
        }
    }
}

Take a look at lines 17 and 22 in the code sample from Program.cs.  The calls to Application.Run(Form) start a message loop on the current thread enabling the form to receive Windows messages.  Application.Run(Form) essentially says to Windows, “Here take this form and show it to the user.”  The form that is supplied can launch other child forms but when it dies so does the whole application.

My goal this week has been to make Sally’s job a little easier by removing the secondary screen and building its functionality into the third screen.  Now normally this would be as simple as replacing line ten with Application.Run(new ThirdForm());.  However that will not work in this case because the third form has a very useful “New Window” button.

Oh, it will work just fine for a while. Sally can click the button leaving her with two views of the application. However the message loop is only hooked up to the first form and if it is closed both forms will die off.

The solution to this problem is in an overload to the Application.Run method that takes an ApplicationContext property. In fact the documentation at MSDN shows a partial solution to my problem.

Instead of supplying Windows with a Form to display to the user I now supply a custom ApplicationContext object.  This custom context can manage the new window call and keep the application alive no mater which form is closed.

Context.cs

/// 
/// Does the work of firing off new application windows.
/// 
internal class Context : ApplicationContext
{
    // The number of windows currently open
    private int mWindowCount;

    /// 
    /// Initializes a new instance of the  class.
    /// 
    public Context()
    {
        this.NewWindow();
    }

    /// 
    /// Creates and shows a new window.
    /// 
    public void NewWindow()
    {
        NewWindow window = new NewWindow(this);

        window.FormClosed += new FormClosedEventHandler(window_FormClosed);

        ++this.mWindowCount;

        window.Show();
    }

    // Close out the application when all windows have been exited
    private void window_FormClosed(object sender, FormClosedEventArgs e)
    {
        NewWindow window = sender as NewWindow;            
        if (window != null)
        {
            window.FormClosed -= this.window_FormClosed;
        }

        --this.mWindowCount;

        if (this.mWindowCount <= 0)
        {
            this.ExitThread();
        }
    }
}

It's important to note that this object knows how many windows there are.  Also note that as each window is created by NewWindow() a listener is added to the FormClosed event.  These two elements allow the context to know when the last form is closed and therefore when to finally exit.

Full source code for the project.