7

I have 3 forms in my C# application -- Form1, Form2 and Form3. Currently when my application starts it loads up Form1. I want all three forms to open on application startup.

I tried doing this in Program.cs:

static void Main()
{     
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
    Application.Run(new Form2());
}

but Form2 only shows up after Form1 is closed.

How can I make all 3 forms show up simultaneously as soon as the application starts?

Zev Spitz
  • 13,950
  • 6
  • 64
  • 136
Casper_2211
  • 1,075
  • 5
  • 14
  • 25

4 Answers4

22

Generally, the right way to have your application do something other than the default (open a form, wait for it to close, then exit) is to make a class that inherits from ApplicationContext. Then you pass an instance of your class to the Application.Run method. When the application should close, call ExitThread() from within your class.

In this case, you can create instances of the three forms when the application loads, and register a handler for their Closed events. When each form is closed, the handler will check if there are any other forms still open, and if not will close the application.

The example on MSDN is doing two things:

  1. opening multiple forms and exiting the application when they are all closed
  2. saving the last size and position of the form when each form is closed.

A simpler example, which closes the application only after all the forms are closed:

class MyApplicationContext : ApplicationContext {
    private void onFormClosed(object sender, EventArgs e) {
        if (Application.OpenForms.Count == 0) {
            ExitThread();
        }
    }

    public MyApplicationContext() {
        //If WinForms exposed a global event that fires whenever a new Form is created,
        //we could use that event to register for the form's `FormClosed` event.
        //Without such a global event, we have to register each Form when it is created
        //This means that any forms created outside of the ApplicationContext will not prevent the 
        //application close.

        var forms = new List<Form>() {
            new Form1(),
            new Form2(),
            new Form3()
        };
        foreach (var form in forms) {
            form.FormClosed += onFormClosed;
        }

        //to show all the forms on start
        //can be included in the previous foreach
        foreach (var form in forms) {
            form.Show();
        }

        //to show only the first form on start
        //forms[0].Show();
    }
}

Then, your Program class looks like this:

static class Program {
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MyApplicationContext());
    }
}

The application closing logic can obviously be customized - are any forms still open, or only one of these three types, or only the first three instances (that would require holding a reference to the first three instances, possibly in a List<Form>).

Re: global event for each form creation -- this looks promising.

A similar example here.

Zev Spitz
  • 13,950
  • 6
  • 64
  • 136
  • The accepted answer is wrong. It causes form1 to be a lead form. This allows each form to be the application until all are removed. The Race-Condition spoke of will likely never happen, put a lock-object around the remove statement if you absolutely have to worry about it. – jerrylagrou Jun 27 '13 at 18:13
  • 2
    Because the forms are all created on the same thread, there is no race condition. UI event processing happens sequentially on the UI thread. – Ben Voigt Aug 12 '14 at 20:25
10

Start the other forms from the Form.Load event of Form1.

private void Form1_Load(object sender, EventArgs e)
{
    Form2 form2 = new Form2();
    form2.Show();
}
Albin Sunnanbo
  • 46,430
  • 8
  • 69
  • 108
  • The only thing with this is, how does he know when the program is to close? According to the user, he can close any window at any time. – DJ Burb Nov 15 '12 at 21:07
  • @DJBurb Where does he specify the desired close behavior? Should the application end when *all* 3 are closed, when *any* 3 are closed, or when a particular form is closed? One, or any, are both easy. All would be a tad more work. – Servy Nov 15 '12 at 21:10
  • I think you need to figure that out yourself, but you can use the [`Form.FormClosing`](http://msdn.microsoft.com/en-us/library/system.windows.forms.form.formclosing.aspx) event to find when a form is beeing closed, abort the closing and hide the form instead. When all forms are hidden, close the application. – Albin Sunnanbo Nov 15 '12 at 21:10
  • @AlbinSunnanbo If you want to wait for all forms to close your best bet would probably to have the main form be a blank hidden form, rather than any one of the regular forms. have it open all 3 and subscribe to the closing event, and then end when they're all closed. – Servy Nov 15 '12 at 21:11
  • @Servy He mentioned it in another reply. I think it was erased – DJ Burb Nov 15 '12 at 21:18
  • @DJBurb Yeah, I see that now. – Servy Nov 15 '12 at 21:19
  • @Servy - inherit from ApplicationContext; see my answer. – Zev Spitz Nov 15 '12 at 21:33
-1

also you can use 3 Tabs whit one form Instead of 3 forms

Mas Jamie
  • 159
  • 2
  • 10
-1

I found my solution by slightly modifying Zev Spitz's answer.

Note: This version only starts the first form specified in the Forms list.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;

class MyApplicationContext : ApplicationContext
{
    public List<Form> Forms = new List<Form>() {
        new Form1()
    };

    private List<Form> FormCollectionToList(FormCollection fc)
    {
        List<Form> ff = new List<Form>();
        foreach (Form f in fc)
        {
            ff.Add(f);
        }
        return ff;
    }

    private void onFormClosed(object sender, EventArgs e)
    {
        Forms = FormCollectionToList(Application.OpenForms);
        if (Forms.Count == 0)
        {
            ExitThread();
        }
        foreach (var form in Forms)
        {
            form.FormClosed -= onFormClosed;
            form.FormClosed += onFormClosed;
        }
    }

    public MyApplicationContext()
    {
        if (Forms.Count == 0)
        {
            Process.GetCurrentProcess().Kill();
        }
        Forms[0].FormClosed += onFormClosed;
        Forms[0].Show();
    }
}

And this version starts all of them.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;

class MyApplicationContext : ApplicationContext
{
    public List<Form> Forms = new List<Form>() {
        new Form1()
    };

    private List<Form> FormCollectionToList(FormCollection fc)
    {
        List<Form> ff = new List<Form>();
        foreach (Form f in fc)
        {
            ff.Add(f);
        }
        return ff;
    }

    private void onFormClosed(object sender, EventArgs e)
    {
        Forms = FormCollectionToList(Application.OpenForms);
        if (Forms.Count == 0)
        {
            ExitThread();
        }
        foreach (var form in Forms)
        {
            form.FormClosed -= onFormClosed;
            form.FormClosed += onFormClosed;
        }
    }

    public MyApplicationContext()
    {
        if (Forms.Count == 0)
        {
            Process.GetCurrentProcess().Kill();
        }
        foreach (var form in Forms)
        {
            form.FormClosed += onFormClosed;
            form.Show();
        }
    }
}
  • You don't need the `FormsCollectionToList` function. You can write `var openForms = Application.OpenForms.Cast
    ().ToList();`.
    – Zev Spitz Aug 15 '14 at 10:10
  • Also, what is the point in checking `Forms.Count` in the constructor? When will it ever be 0? – Zev Spitz Aug 15 '14 at 10:11
  • Your use of `Application.OpenForms` suggests it is possible to get rid of the private `List
    ` field. See my updated answer.
    – Zev Spitz Aug 15 '14 at 10:28
  • Why do you need to unregister and reregister the `onFormClosed` event handler for **all** the open forms each time **any** form is closed? – Zev Spitz Aug 15 '14 at 10:31
  • Unless you are concerned with new forms that will be created outside of `MyApplicationContext`? If that is the case then that should be the primary focus of your answer. -1. – Zev Spitz Aug 20 '14 at 18:17
  • Also, I do need the FormsCollectionToList function. The FormCollection class does not have a Cast function. – Connor DeRivera Aug 21 '14 at 11:19
  • Anything that implements `IEnumerable` can use the `.Cast` extension method. Add `using System.Linq;` to the top of your code file. – Zev Spitz Aug 21 '14 at 22:59