geronimo
geronimo

Reputation: 21

Form.Close() doesn't close window immediately

I need to be sure that all forms will be closed if I user somehow close the main form. So I decided to hide Close() function and I wrote something like this

public new bool Close()
        {
            List<Form> formsList = new List<Form>(Application.OpenForms.Count);
            foreach (var form in Application.OpenForms)
                formsList.Add((Form)form);
            formsList.Reverse();
            foreach (var form in formsList)
            {
                if (form.IsDisposed) continue;
                Invoke(new GenericEventHandler(() => { form.Close(); }));
            }

            return Application.OpenForms.Count == 0;
        }

So if all forms are closed successfully I return true and thanks to this I know that user can be logged out from application.

However it seems that form.Close() function is not fired immediately. After calling form.Close() formclosed event is not fired immediately as well as collection Application.OpenForms is not modified. The amount of opened forms is noted changed.

What could be a reason?

Upvotes: 2

Views: 769

Answers (5)

HypnoToad
HypnoToad

Reputation: 605

If for some reason, Application.Exit isn't cutting it for you, you could try this code (put it in the form's FormClosing event):

while (Application.OpenForms.Count > 1)
{
  Form form = Application.OpenForms[1];
  form.Close();
  while (!form.IsDisposed) Application.DoEvents();
}

or if you want it to time out if it can't close all the forms after a while,

while (Application.OpenForms.Count > 1)
{
  Form form = Application.OpenForms[1];
  form.Close();
  DateTime StartTime = DateTime.Now;
  while (!form.IsDisposed && (StartTime - DateTime.Now).TotalMilliseconds < 1000)
    Application.DoEvents(); //1-second timeout here
  if (!form.IsDisposed) //if it's still not closed
  {
    //send a message to the user that the application can't exit right now
    mbox("some forms are still open or whatever");
    e.Cancel = true;
    return;
  }
}

Upvotes: 0

rudolf_franek
rudolf_franek

Reputation: 1885

In general I suggest not to use new keyword to any members of Control and/or Form class. If you need your own method use your own name of it.

In your code you don't really need to use Invoke when closing child forms.

If you need to be sure that all your child Forms are closed before you actually execute logic related to MainForm.Close you may subscribe to MainForm.FormClosing event with handler similar to follwing:

void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    bool allChildFormsClosed = !closeAllChildForms();

    if(!allChildFormsClosed)
    {
        e.Cancel = true;
        MessageBox.Show("Failed to close one or more child forms.");
        // better add some yes|no dialog to force exit if necessary
    }
}

You may implement closeAllChildForms in a similar way as you did above - just: remove the formsList.Reverse(); and the 'Invoke..' - just call Close directly and update: if (this == form || form.IsDisposed) continue;

Upvotes: 0

Vladimir
Vladimir

Reputation: 3689

Well, if the user closes the main form, then upon closing it your application will definitely exit, since your form is responsible for keeping the application alive when it was passed to Application.Run().

Now, if you want to close your app when a form is closed, in that form you do this:

protected override void OnFormClosed(FormClosedEventArgs e)
{
    base.OnFormClosed(e);
    Application.Exit();
}

Upvotes: 1

Marshal
Marshal

Reputation: 6651

Why dont you just use

Application.Exit();

Upvotes: 5

Adam Houldsworth
Adam Houldsworth

Reputation: 64477

If the main form is created in the standard way in WinForms via Application.Run(new MainForm()); then when it closes, the application will exit, closing all other forms. So I don't think you need to worry about manually closing all child forms.

Upvotes: 1

Related Questions