为什么我得到一个异常"不能访问已处置的对象"有时
本文关键字:访问 不能 有时 对象 异常 一个 为什么 | 更新日期: 2023-09-27 18:02:55
我有这个代码在我的背景DoWork
事件:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (true)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
if (tempCpuValue >= (float?)nud1.Value || tempGpuValue >= (float?)nud1.Value)
{
soundPlay = true;
blinking_label();
NudgeMe();
}
else
{
soundPlay = false;
stop_alarm = true;
}
cpuView();
gpuView();
}
}
}
在cpuView()
方法中,我有以下代码:
if (InvokeRequired)
{
this.Invoke(new Action(() => data = new List<string>()));
this.Invoke(new Action(() => data.Add("Gpu Temeprature --- " + sensor.Value.ToString())));
this.Invoke(new Action(() => listBox1.DataSource = null));
this.Invoke(new Action(() => listBox1.DataSource = data));
this.Invoke(new Action(() => listBox1.Invalidate()));
}
异常/错误出现在这一行:
this.Invoke(new Action(() => data = new List<string>()));
这是Form1的关闭事件:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (MessageBox.Show("Are you Sure you want to Exit. Click Yes to Confirm and No to continue", "WinForm", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
{
e.Cancel = true;
}
else
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
backgroundWorker1.CancelAsync();
}
}
}
错误/异常发生在我退出应用程序时,点击右上角的红色x并选择YES退出。
所以这里的部分问题是您没有利用BGW提供给您的功能。如果你从DoWork
内部调用Invoke
,这意味着你并没有真正使用BGW来完成它的工作。在你的情况下,你应该只是在BGW上调用ReportProgress
,然后有一个ProgressChanged
事件处理程序,根据进度更新UI。你可以传入一个参数来表示要更新UI的数据,这样你就可以在DoWork
中构造你的列表,通过ReportProgress
传递它,然后在ProgressChanged
事件处理程序中设置DataSource
。
现在BGW负责在工人被取消后不报告进度。
当窗体关闭时,它的子控件和窗体本身将被清除。然而,WinForms继续在UI线程上处理挂起的调用。这就是为什么它会抛出"不能访问已处置的对象"。
Application.DoEvents()
通常被描述为邪恶,但它的工作是处理UI线程上所有挂起的消息。
在Close事件中完成后台线程是不够的。
这就是为什么我建议你在任何处置之前添加一个Application.DoEvents()
,所以挂起的调用被刷新,然后表单将优雅地关闭。
if (MessageBox.Show("Are you Sure you want to Exit. Click Yes to Confirm and No to continue", "WinForm", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
{
e.Cancel = true;
}
else
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
backgroundWorker1.CancelAsync();
}
Application.DoEvents();
}
如果Application.DoEvents()对您来说太复杂,您可以使用封装了invokerrequired模式的扩展方法来吞下ObjectDisposedException:
public static void InvokeIfRequired(this Control control, Action action)
{
try
{
if (control.IsDisposed)
return;
if (control.InvokeRequired)
control.Invoke(action);
else
action();
}
catch (ObjectDisposedException)
{
// There is nothing much we can do when an Invoke is pending on a disposed control
// the other exceptions will bubble up normally
}
}