Avoid calling Invoke when the control is disposed

2019-01-09 05:15发布

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?

14条回答
\"骚年 ilove
2楼-- · 2019-01-09 06:12

You could use mutexes.

Somewhere at the start of the thread :

 Mutex m=new Mutex();

Then :

if (mImageListView != null && 
    mImageListView.IsHandleCreated &&
    !mImageListView.IsDisposed)
{
    m.WaitOne(); 

    if (mImageListView.InvokeRequired)
        mImageListView.Invoke(
            new RefreshDelegateInternal(mImageListView.RefreshInternal));
    else
        mImageListView.RefreshInternal();

    m.ReleaseMutex();
}

And whereever it is you are disposing of mImageListView :

 m.WaitOne(); 
 mImageListView.Dispose();
 m.ReleaseMutex();

This should ensure you cant dispose and invoke at the same time.

查看更多
该账号已被封号
3楼-- · 2019-01-09 06:14

The solution proposed by Isak Savo

try
  {
  myForm.Invoke(myForm.myDelegate, new Object[] { message });
  }
catch (ObjectDisposedException)
  { //catch exception if the owner window is already closed
  }

works in C# 4.0 but for some reasons it fails in C#3.0 (the exception is raised anyway)

So I used another solution based on a flag indicating if the form is closing and consequently preventing the use of invoke if the flag is set

   public partial class Form1 : Form
   {
    bool _closing;
    public bool closing { get { return _closing; } }

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        _closing = true;
    }

 ...

 // part executing in another thread: 

 if (_owner.closing == false)
  { // the invoke is skipped if the form is closing
  myForm.Invoke(myForm.myDelegate, new Object[] { message });
  }

This has the advantage of completely avoiding the use of try/catch.

查看更多
登录 后发表回答