Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Closing a form from the Load handler

I have a very strange behavior that only seems to happen on one form.

Basically I am creating an instance of a Form, and calling Show() to display the form non-blocking. In that form's Load event handler, I have some logic that may call this.Close() under certain circumstances. This closes the form, but then the form Show() method in the client code throws an ObjectDisposedException.

The stack trace from the ObjectDisposedException is as follows:

at System.Windows.Forms.Control.CreateHandle()
at System.Windows.Forms.Form.CreateHandle()
at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.ContainerControl.FocusActiveControlInternal()
at System.Windows.Forms.Form.SetVisibleCore(Boolean value)
at System.Windows.Forms.Control.Show()
...etc.

This is what I'm seeing happen:

  1. Control.Show() is called
  2. my form is launched
  3. the OnFormLoad method is called
  4. the FormLoad event handler is called, inside of which I call this.Close()
  5. the OnFormClosing method is called
  6. the FormClosing event handler is called
  7. Dispose is called on my form and all it's user controls

and then somewhere toward the end of the Control.Show() method, it tries to get a handle to the form, which freaks out and throws an exception because the object is marked disposed.

My real question is, why can I do this exact same thing on every other form I have without exceptions? Is it a GC issue? I've tried putting a GC.Collect() call right after the this.Close() and it makes no difference. Like I said, it happens 100% of the time on this form, and never anywhere else, regardless of child user controls, scope of the form variable, etc.

Any ideas?

like image 443
LoveMeSomeCode Avatar asked Apr 08 '09 17:04

LoveMeSomeCode


3 Answers

The best way to do so :

 this.BeginInvoke(new MethodInvoker(this.Close));

this is the most simple way you wont get ObjectDisposedException

like image 150
RcMan Avatar answered Oct 07 '22 00:10

RcMan


protected override void CreateHandle()
   {
        base.CreateHandle();

        if (FormMustClose)  //FormMustClose is a variable in the loadevent.
        {
            Close();
        }
    }
like image 24
Dominican Avatar answered Oct 07 '22 00:10

Dominican


Ok, hate to answer my own question, but this was driving me nuts, and it was one of the hardest bugs to reproduce I've ever seen.

On my form I'm overriding the OnFormLoad and OnFormClose methods, where I save/restore the form's Size, Location, and WindowState to/from the registry. I took this code out and it fixed the problem. The weird thing is, I put it back and the problem didn't come back.

I finally reproduced the problem: you have to let the form open fully, maximize it, and then close it so that the Maximized state is saved to the registry. Then when you open it again, it will set it to Maximized, and if it closes in the Load handler, it tries to access the Size/Location as it's closing. Apparently accessing these values in the OnFormClosing method causes the form to try to focus IF AND ONLY IF the form is maximized, which is illegal, since the form has been disposed.

So basically, you can't access Form display properties in the OnFormClosing method of a form, if that form is going to call Close from it's Load event.(Unless you check the Disposed prop first)

pretty specific piece of Winforms wisdom I know, but I'm writing it down anyway.

like image 21
LoveMeSomeCode Avatar answered Oct 07 '22 01:10

LoveMeSomeCode