我的后台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并选择“是”退出,就会发生错误/异常。
我该怎么办?
答案 0 :(得分:1)
因此,部分问题在于您没有利用BGW为您提供的功能。如果您从Invoke
内部呼叫DoWork
,则意味着您并没有真正使用BGW来完成它的工作。在您的情况下,您应该只是在BGW上调用ReportProgress
,然后有一个ProgressChanged
事件处理程序,根据进度更新UI。您可以传入代表数据的参数来更新用户界面,以便您可以在DoWork
内构建列表,通过ReportProgress
传递,然后在DataSource
中设置ProgressChanged
{{1}}事件处理程序。
现在,BGW负责在工人被取消后不报告进度。
答案 1 :(得分:0)
当一个表格关闭时,它的子控件和表单本身就被处理掉了。但是,WinForms继续在UI线程上处理挂起的Invokes。这就是它引发“无法访问被处置对象”的原因。
Application.DoEvents()
通常被描述为邪恶,但它的工作是处理UI线程上的所有待处理消息。
在Close事件中完成后台线程是不够的。
这就是为什么我建议你在任何Dispose之前添加一个Application.DoEvents()
,所以正在刷新挂起的Invokes,然后表格将正常关闭。
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()对您来说过于苛刻,您可以使用封装InvokeRequired模式的扩展方法来吞下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
}
}