0
votes

I have a MDI main form. On it I host a form, and I want it to show a message box before it closes (asking the user whether to save changes).

So far so good, however I have discovered that closing the MDI main form does not raise a MDI child FormClosing event. I figured I will just call MdiChild.Close() in the MDI main's FormClosing event (which does get raised). This seams to work, however it does causes a problem...

In the messagebox that I show, I offer the user to save changes, not to save changes and cancel closing. Normally this works fine, however I can't seem to find a way to cancel MDI main's FormClosing event. Is there a elegant way of doing this?

EDIT: I solved this by throwing an exception (when user decides to cancel the closing procedure) which is caught in MDI main's FormClosing event. In this way I know when I have to cancel the MDI main's FormClosing event and this seams to work fine ... However I just can't believe that this "hax" is the only way of doing this. Surely there is a better way?

3

3 Answers

3
votes

I figure that you cancel the close on the childform when the user votes to cancel the close?

In that case I'd go with this Main form close

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    if (e.CloseReason == CloseReason.UserClosing)
    {
        foreach (Form frm in this.MdiChildren)
        {
            frm.Close();
        }
    }
    e.Cancel = (this.MdiChildren.Length > 0);
}
1
votes

I'd suggest that instead of calling Close on the childforms you could create a method like ReadyToClose in the child forms and then the main form loops through and calls that for each of the child forms and it'll ask the question to the user and do the saving if needed and finally it'll return true if ok to continue.

And if all of the child forms "vote" for a close, then you close it all down, otherwise you close nothing.

1
votes

When closing the MDI main form, all child Close events are called first so, when calling frm.Close() on the foreach loop, Close events for the child are called again (I don't know why if they should be already closed).

ho1 suggestion worked pretty well for me. Here is my modified foreach loop (ClosableMDIChildForm is an interface which contains the IsOkToClose() method):

foreach (ClosableMDIChildForm cmdif in this.MdiChildren)
{
    if (!cmdif.IsOkToClose())
    {
        e.Cancel = true;
        ((Form)mdifc).Focus();
        break;
    }
}

Obviously, this.MdiChildren forms must implement ClosableMDIChildForm interface. The logic to decide if it's OK to close the window goes in the implementation of IsOkToClose().