views:

105

answers:

3

I have a form in a Windows form application that I want to display on top of a main form, close it, and then immediately show a dialog box using MessageBox.Show(). But the first form is still showing when the message box is shown, and it does not disappear until I click OK on the message box. I tried waiting to show the message box in an event handler for the form's VisibleChanged event and even calling Refresh() on both the form and the main form. Is there a way I can determine when the first form has fully disappeared before displaying the message box?

Edit:

Here is some code that demonstrates how the forms are being shown.

static class Program
{
    // The main form is shown like this:
    static void Main()
    {
        Application.Run(new MainForm());
    }
}

public class Class1 
{
    // _modalForm is the first form that is displayed that won't fully go away 
    // when it is closed.
    ModalForm _modalForm;
    BackgroundWorker _worker;

    public Class1()
    {
        _modalForm = new ModalForm();
        _worker = new BackGroundWorker();
        _worker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted
    }

    public void Method1()
    {
        _worker.RunWorkerAsync();

        // The first form is shown.
        _modalForm.ShowDialog();
    }


    // This code runs in the UI thread.         
    void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        _modalForm.VisibleChanged += new EventHandler(_modalForm_visibleChanged);
        _modalForm.Close();
    }

    void _modalForm_visibleChanged(object sender, EventArgs e)
    {
        // When the message box is shown, the other form is still visible
        // and remains so until I click OK.
        MessageBox.Show("The other form was just closed.");

        // Note:  I originally tried to use the FormClosed event instead of
        // VisibleChanged.  Then I tried Deactivate, in attempt to use an event
        // that occurred later thinking that might do the trick.  VisibleChanged
        // is the latest event that I found.
        // 
    }
+2  A: 

The Form.FormClosed event is raised when the form completes closing. At this point, all Form.FormClosing event handlers have been run, and none of them canceled the close.

Form.FormClosed replaced Form.Closed (which is deprecated) in the .NET 2.0 framework.

R. Bemrose
+4  A: 

I'll guess that you are running your code on Windows XP or Vista/Win7 with Aero turned off. Closing a form does not make the pixels on the screen disappear instantly. The Windows window manager sees that the window for the form got destroyed and that this revealed parts of other windows underneath it. It will deliver a WM_PAINT message to let them know that they need to repaint the parts of the window that got revealed.

This will not work properly if one or more of those windows isn't actively pumping a message loop. They can't see the WM_PAINT message. They won't repaint themselves, the pixels of the closed form will remain on the screen.

Find out why these windows are not responding. Hopefully it is your window and the debugger can show you what the UI thread is doing. Make sure it isn't blocking on something or stuck in a loop.


After seeing the edit: there's indeed blocking going on, of a different kind. The MessageBox.Show() call is modal, it prevents the VisibleChanged event from completing. That delays the closing of the form.

Use System.Diagnostics.Debug.WriteLine() or Console.WriteLine() to get diagnostics in a Window Forms app. You'll see it in the Output window. Or simply use a debugger breakpoint.

Hans Passant
I am indeed using Windows XP. I edited my question to include some code. I don't believe the UI thread is blocking, and I am not sure I completely understand what it means for a thread to be "stuck in a loop," but would the fact that the form is being shown modally have anything to do with it?
YWE
@YWE: the MessageBox.Show() call is simply blocking the VisibleChanged event, preventing the normal form shutdown from completing. Never use MessageBox for debugging in a WF app, use Debug.WriteLine().
Hans Passant
@ Hans Passant: Ah, so the VisibleChanged event has to completely finish before the form completely goes away. The message box actually is part of the program and not a debugging aid. I tried the same program using the Dispose event instead and it works like I want. Thanks.
YWE