Note that there are some explanatory texts on larger screens.

plurals
  1. POObjectDisposedException on call to Form's Invoke when it hasn't been Disposed
    primarykey
    data
    text
    <p>We get an <code>ObjectDisposedException</code> from a call to <code>Invoke</code> on a Form that hasn't yet been disposed. Here's some sample code demonstrating the problem:</p> <pre><code>public partial class Form2 : Form { void Form2_Load(object sender, EventArgs e) { // Start a task that does an Invoke on this control Task.Factory.StartNew(TaskWork); // Sleep here long enough to allow the task that does the Invoke // to execute to the point where it has: // a. Posted the message and // b. is waiting Thread.Sleep(500); // Cause ShowDialog to return by setting the DialogResult DialogResult = DialogResult.OK; } void TaskWork() { // This call doesn't return, but instead throws an ObjectDisposedException this.Invoke((MethodInvoker)(() =&gt; MessageBox.Show("Invoke succeeded"))); } } </code></pre> <p>Here's the calling code from Form1 (the main form) which I never close:</p> <pre><code>public partial class Form1 : Form { Form2 m_form2 = new Form2(); void Form1_Load(object sender, EventArgs e) { // Call ShowDialog, but don't dispose it. m_form2.ShowDialog(); // Cause the finalizers to run. This causes an AggregateException to be thrown // due to the unhandled ObjectDisposedException from the Task. GC.Collect(); } } </code></pre> <p>We dug in to the Microsoft source, and found the exception is created during the call to DestroyHandle (below). DestroyHandle is being called by ShowDialog as it is finishing.</p> <p>From source.NET\4\DEVDIV_TFS\Dev10\Releases\RTMRel\ndp\fx\src\WinForms\Managed\System\WinForms\Control.cs\1305376\Control.cs:</p> <pre><code>protected virtual void DestroyHandle() { // ... // If we're not recreating the handle, then any items in the thread callback list will // be orphaned. An orphaned item is bad, because it will cause the thread to never // wake up. So, we put exceptions into all these items and wake up all threads. // If we are recreating the handle, then we're fine because recreation will re-post // the thread callback message to the new handle for us. // if (!RecreatingHandle) { if (threadCallbackList != null) { lock (threadCallbackList) { Exception ex = new System.ObjectDisposedException(GetType().Name); while (threadCallbackList.Count &gt; 0) { ThreadMethodEntry entry = (ThreadMethodEntry)threadCallbackList.Dequeue(); entry.exception = ex; entry.Complete(); } } } } // ... } </code></pre> <h1>Questions:</h1> <ol> <li><p>Why is ShowDialog destroying the handle (when I might re-use this form)?</p></li> <li><p>Why am I getting an ObjectDisposedException--its very misleading (since its not disposed). Its as if the code expected the handle would be destroyed only when the object was disposed (which is what I was expecting).</p></li> <li><p>Should this be valid? That is, should I be allowed to Invoke on to a control after ShowDialog?</p></li> </ol> <h1>Notes:</h1> <ol> <li><p>Doing a second <code>.ShowDialog()</code> causes a new handle to be created.</p></li> <li><p>If after doing <code>.ShowDialog()</code> I try to do an <code>Invoke</code>, I get an InvalidOperationException stating that "Invoke or BeginInvoke cannot be called on a control until the window handle has been created."</p></li> <li><p>If after doing <code>.ShowDialog()</code> I access the <code>Handle</code> property, and then do an <code>Invoke</code>, it will succeed.</p></li> </ol>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload