Form.ShowDialog() called from MDI child form blocking other forms

27 Views Asked by At

I have a winforms project. I open a child MDI form from base form / parent form. Then I call form2.ShowDialog(), this freezes parent form and all other forms until the ShowDialog() is completed.

I want only the child form from which the ShowDialog() is called to freeze. I want other forms to be available and accessible.

1

There are 1 best solutions below

0
Harald Coppoolse On

You have to be aware that there are two forms of Dialog boxes: modal dialog boxes and modeless dialog boxes

  • Modal dialog box: stop all user interaction with all other forms of the application until the Modal dialog box is closed. To use this dialog box use one of the overloads of Form.ShowDialog
  • Modeless dialog box: a new Form is shown. This Form gets the focus, as if Form.Activate has been called. The operator can switch the focus between the new form and the other forms of your application. To show a modeless dialog box use Form.Show

From the description above, you can gather that you are showing a modal dialog box. To be able to switch the focus to the other forms, you should use Form.Show, instead of Form.ShowDialog.

There is something extra in your code: you only want the Child form to freeze, not the other forms of your application. The standard method is to Disable the child form before showing the modeless dialog box, and to Enable the child form after the modeless dialog box has been closed.

You forgot to give us some code, so I don't know which form will show the modeless dialog box. Usually the dialog box is shown by clicking on something in the child form that must be disabled. Code would look like this:

// reference to existing Modeless dialog box
MyModelessDialogBox MyModelessDialogBox {get; set;} = null;

void ShowMyModelessDialogBox(...)
{
    // disable myself:
    this.Enabled = false;

    // create the modeless dialog box, set some properties
    this.MyModelessDialogBox = new MyModelessDialogBox();
    this.MyModelessDialogBox.Property = ...

    // you need to know when the modeless dialog box is closed
    this.MyModelessDialogBox.Closed += this.OnMyModelessDialogBoxClosed;

    // show it as modeless:
    this.MyModelessDialogBox.Show(this);  // I am the parent form
}

Consider to add a check in the beginning of this method to be sure that MyModelessDialogBox does not exist yet.

When the modeless dialog box has been closed, the event handler will be called:

void OnMyModelessDialogBoxClosed(object sender, System.EventArgs e)
{
    // not really needed, just to be certain:
    if (!Object.ReferenceEquals(this.MyModelessDialogBox, sender)
    {
        .. // hmm, what to do? Exception? Ignore?
    }

    // if here, I know that this.MyModelessDialog just has been closed.
    // it still exists, so I can get information about it.
    MyDialogResult dlgResult = this.MyModelessDialogBox.GetDlgResult();
    this.ProcessMyDialogResult(dlgResult);

    // I don't need the modeless dialog box anymore, Dispose it:
    this.MyModelessDialogBox.Dispose();
    this.MyModelessDialogBox = null;

    // Enable myself
    this.Enabled = true;
}

Things to consider

If your modeless dialog box is shown, the operator could decide to close your application, or shutdown windows. In that case, you'll have to close MyModelessDialog.

However, the operator might just have been started something very important on the Modeless dialog box. Standard behaviour would be to warn the operator and to give him the opportunity to cancel the shutdown. Compare this to closing an application while you forgot to save the file.

If your application is about to be closed, event Form.Closing is raised. Consider to add an event handler for this event. In the event handler you can check if MyModelessDialogBox exists, and if so, you can ask it to close itself. The modeless dialog box will do the standard things when being closed, for instance ask the operator to save the data, or something else. If the modeless dialog box can't be closed, the closing program should be cancelled.

Code in the form that created the modeless dialog box would be like this:

private void OnFormClosing(Object sender, FormClosingEventArgs e)
{
    if (this.MyModelessDialogBox != null)
    {
        // MyModelessDialogBox still exists. Ask it to close itself
        this.MyModelessDialogBox.Close();

        // This will lead to event FormClosing on the modeless dialog box.
        // If closing allowed, event FormClosed will be raised, which will call
        // the event handler described above. This event handler will process
        // the results and assign null to this.MyModelessDialogBox.
        // if the modeless dialog box can't be closed, for instance because the 
        // operator presses cancel, then FormClosed will return with event arg
        // Canceled treu. Event FormClosed will not be raised.
        // So if this.MyModelessDialogBox is still not null, then I know that
        // Closing is cancelled.
        
        // do you need to do something if the closing has been cancelled?
        if (this.MyModelessDialogBox != null)
        {
            ...
        }

        // if closing of the modeless dialog box is cancelled,
        // = if the modeless dialog box still exists
        // then my closing should also be cancelled.
        e.Cancelled = this.MyModelessDialogBox != null;
    }
}

It is up to your modeless dialog box to decide what to do when it is to be closed. Maybe throw away all input data, or save it for the next time? Ask the operator if closing is ok, or if data must be saved? The modeless dialog box can check why the dialog box is closed via property FormClosingEventArgs.CloseReason