Problems solving “Cannot access disposed object.” exception

不问归期 提交于 2019-12-01 02:55:49

There are two workarounds: either swallow the exception and curse Microsoft for not having included a TryInvoke and TryBeginInvoke methods, or else use locking to ensure that no attempt is made to Dispose the object while it's in use, and no attempt is made to use the object while Dispose is in progress. I think swallowing the exception is probably better, but some people have a visceral reaction against such things, and using locking it is possible to avoid having the exception occur in the first place.

One problem is that you are doing the check on the timer thread, before calling Invoke. There is a possible race condition, where the Form can be disposed after your check and before the invoked action is executed.

You should be doing the check inside the method (lambda expression in your case) called by Invoke.

Another possible problem is that you're accessing Cursor.Position on the timer thread. I'm not sure if this is valid - I'd do this on the main thread. Your code also includes the comment //some code - so you've presumably omitted some code that you also need to check.

Overall, you'd probably be better using a System.Windows.Forms.Timer.

Here is my solution to your exception if you are interested:

private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            timer.Stop();
            Application.DoEvents();       
        }

.Stop() without .DoEvents() is not enough, as it'll dispose objects without waiting for your thread to finish its work.

Create two booleans called 'StopTimer' and 'TimerStopped' with their initial states set to false. Set the timer's AutoReset property to false. Then format the Elapsed method to the following:

Invoke((MethodInvoker)delegate {
    // Work to do here.
});
if (!StopTimer)
    timer.Start();
else
    TimerStopped = true;

This way you are preventing a race condition, checking if the timer should continue and reporting when the method has reached its end.

Now set your FormClosing method to this:

if (!TimerStopped)
{
    StopTimer = true;
    Thread waiter = new Thread(new ThreadStart(delegate {
        while (!TimerStopped) { }
        Invoke((MethodInvoker)delegate { Close(); });
    }));
    waiter.Start();
    e.Cancel = true;
}
else
    timer.Dispose();

If the timer hasn't stopped yet, a thread is launched to wait until it has done so and then try to close the form again.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!