Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid calling Invoke when the control is disposed

I have the following code in my worker thread (ImageListView below is derived from Control):

if (mImageListView != null &&      mImageListView.IsHandleCreated &&     !mImageListView.IsDisposed) {     if (mImageListView.InvokeRequired)         mImageListView.Invoke(             new RefreshDelegateInternal(mImageListView.RefreshInternal));     else         mImageListView.RefreshInternal(); } 

However, I get an ObjectDisposedException sometimes with the Invoke method above. It appears that the control can be disposed between the time I check IsDisposed and I call Invoke. How can I avoid that?

like image 434
Ozgur Ozcitak Avatar asked Dec 09 '09 15:12

Ozgur Ozcitak


2 Answers

What you have here is a race condition. You're better off just catching the ObjectDisposed exception and be done with it. In fact, I think in this case it is the only working solution.

try {     if (mImageListView.InvokeRequired)        mImageListView.Invoke(new YourDelegate(thisMethod));     else        mImageListView.RefreshInternal(); }  catch (ObjectDisposedException ex) {     // Do something clever } 
like image 63
Isak Savo Avatar answered Sep 20 '22 13:09

Isak Savo


There are implicit race conditions in your code. The control can be disposed between your IsDisposed test and the InvokeRequired test. There's another one between InvokeRequired and Invoke(). You can't fix this without ensuring the control outlives the life of the thread. Given that your thread is generating data for a list view, it ought to stop running before the list view disappears.

Do so by setting e.Cancel in the FormClosing event and signaling the thread to stop with a ManualResetEvent. When the thread completes, call Form.Close() again. Using BackgroundWorker makes it easy to implement the thread completion logic, find sample code in this post.

like image 25
Hans Passant Avatar answered Sep 19 '22 13:09

Hans Passant