2

look this please:

var form = new Form();

form.Shown += (_, __) =>
{
    var timer = new System.Windows.Forms.Timer { Interval = 1000 };

    timer.Tick += (x, xx) =>
    {
        timer.Stop();
        GC.KeepAlive(timer);
        timer.Dispose();

        form.Close();

        Application.DoEvents(); // no effect 

        // it will cause form keep show
        MessageBox.Show("asdf");

        // but if this, that's fine
        // BeginInvoke(new Action(() => MessageBox.Show("asdf")));
    };

    timer.Start();
};

form.ShowDialog();

form.Close before MessageBox.Show, but form will not close until close msgBox, please help.

--end--

all in code, why need more words? all in code, why need more words? all in code, why need more words?

4
  • 1
    Close(); != return; Commented Aug 3, 2019 at 11:59
  • Note that, in this code, you're in the same context that started form: Application.DoEvents(); won't affect the special message loop generated when you call Form.ShowDialog(). The WM_Close message will be processed when the method exits. Different from Form.Hide() (same as Form.Visible = false), where the Window's destiny will be decided somewhere else. When you BeginInvoke(), the ThreadMethodEntry that holds the Delegate (Action or MethodInvoker), will be enqueued, causing it to execute after (through PostMessage).
    – Jimi
    Commented Aug 3, 2019 at 12:22
  • Btw, it's not clear what you need help with.
    – Jimi
    Commented Aug 3, 2019 at 12:38
  • @Jimi but if use SynchronizationContext.Current.Post(_=>MessageBox.Show("asdf"), null), it's still block window close. I know WindowsFormsSynchronizationContext.Post use Control.BeginInvoke.
    – ahdung
    Commented Aug 5, 2019 at 1:17

1 Answer 1

2

When you show a form as modal using ShowDialog(), calling Close in fact sends a WM_CLOSE message and then it sets DialogResult to Cancel which acts as a flag for modal message loop to exit the loop.

So Close will not close or hide the modal dialog immediately. Then after finishing the modal message loop, the modal dialog will be hide (but not destroyed).

MessageBox method also blocks the execution of code, so codes after the message box will execute just after closing the message box. So now it's clear why after calling Close, first the MessageBox shows then after closing message box, form closes.

Just to make it easier to understand, here is a pseudo-code which shows what is happening when you call ShowDialog in your code:

Form Shows
While Form.DialogResult != None
{
    Form.Close → Sends WM_CLOSE → Sets Form.DialogResult = Cancel 
    MessageBox.Show and wait until MessageBox closes
}
Form Hides

Just keep in mind, Close is not equal to return, it means the code which you have after Close will run as well. Here the code is MessageBox which blocks the loop until after MessageBox closes.

To hide the dialog immediately, replace the form.Close() with form.Hide(), this way without waiting for the loop, you are commanding the form to get hidden. But it doesn't mean the form has been closed and therefore lines of code which you have after ShowDialog will not run until after the loop finishes.

For more information about how Close and ShowDialog work, you may want to take a look at a Windows Forms source code, specially the following lines:

Not the answer you're looking for? Browse other questions tagged or ask your own question.