Search code examples
c#.netwinformsformclosing

Why does FormClosing fire twice when calling Hide() in modal dialog?


We created a new form that we're showing via ShowDialog and added a "Cancel" button to it. Here's how we're opening the form from its parent:

// _modalForm is a class-level instance of our ModalForm class
var result = _modalForm.ShowDialog(this);
MessageBox.Show(result.ToString());

Here's the cancel button's Click event handler in ModalForm.

private void btnCancel_Click(object sender, EventArgs e)
{
    Close();
}

In our FormClosing event, we have this code (based on this answer).

private void ModalForm_FormClosing(object sender, FormClosingEventArgs e)
{
        e.Cancel = true;
        Hide();
        _parentForm.RefreshData();
}

Surprisingly, when we click the "Cancel" button (or use the "X" button at the top of the form), the FormClosing event is raised twice. Both times the CloseReason is UserClosing.

I double checked to make sure InitializeComponent isn't call twice and that we only subscribe to the event once. btnCancel is not set at the CancelButton property for the form. It also doesn't have DialogResult set in the designer. When I check the return value of ShowDialog though, it is set to DialogResult.Cancel.

Changing btnCancel_Click to just be DialogResult = DialogResult.Cancel instead of Close() and doing nothing except _parentForm.Refresh() in the FormClosing event fixes the issue of the event getting raised twice.

Does anyone know why in this particular scenario the FormClosing event gets raised twice?


Solution

  • That's because hiding a modal form will cause it to close with DialogResult.Cancel as dialog result. So if you call this.Hide() in FormClosing event, the event will be raised again.

    Imagine if it didn't close the form, your application had been blocked by a hidden modal form!

    Note: The answer describes about the reason of raising the event twice. But as described here and others mentioned, For modal forms (which you showed using ShowDialog), the Dispose method will not be called and the form exists after closing and you can use its properties to get some data or you can show it again. So you don't need to call hide method.

    For more information take a look at: Do I need to Dispose a Form after the Form got Closed?