我正在使用WinForm,从中我需要的所有进程都会被引导。现在,我尝试将BackgroundWorker
与ProgressBar
和取消按钮集成到我的代码中。我希望它在我的代码本地,而不是在一个单独的方法。要对此进行测试,将创建一个带有进度条(尚未激活)的新表单和一个用于停止for循环的按钮。但是,代码无法正常工作(甚至还没有包含进度条)。表格立即冻结(见图),因此我无法测试取消按钮。但是,执行for循环并显示"Done: " + l.ToString()
。我该如何解决这个问题?
void stopMeasurement(object sender, EventArgs e)
{
stopMeas = true;
}
public void testcancel() // Test method which is triggered manually
{
int l = 0;
MetingProgress metingProgress = new MetingProgress();
metingProgress.btnCancelmeting.Click += new EventHandler(stopMeasurement);
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.DoWork += (sender, args) =>
{
for (int k = 0; k < 10; k++)
{
Thread.Sleep(1000);
l++;
if (worker.CancellationPending)
break;
}
MessageBox.Show("Done: " + l.ToString());
};
worker.RunWorkerAsync();
while (worker.IsBusy)
{
if (stopMeas)
worker.CancelAsync();
}
metingProgress.Dispose();
MessageBox.Show("All done");
}
答案 0 :(得分:4)
此代码是您的问题:
while (worker.IsBusy)
{
if (stopMeas)
worker.CancelAsync();
}
您的GUI-Thread处于该循环中,直到您的工作完成。 您需要从EventHandler中访问您的worker实例,并从那里调用worker.CancelAsync()。
除此之外,我个人会分两步改进代码:
将整个BackgroundWorker移动到MetingProgress类中,并使其构造函数为实际工作实现提供委托。
使用TAP(任务异步模式),即async / await Task with Progress和CancellationToken。
答案 1 :(得分:4)
表单立即冻结
这是因为您在主线程上仍然运行 while循环!因此表单不会响应。这叫做buisy等待。您将无法调用CancelAsync
方法。
一种解决方案可能是删除while循环并将取消调用放入按钮事件代码中:
void stopMeasurement(object sender, EventArgs e)
{
stopMeas = true;
worker.CancelAsync();
}
你基本上做的是:你创建了第二个取消令牌。因此,另一种可能性是仅使用stopMeas
来取消后台操作:
worker.DoWork += (sender, args) =>
{
for (int k = 0; k < 10; k++)
{
Thread.Sleep(1000);
l++;
if (stopMeas)
break;
}
string mes = stopMeas ? "Done: " + l.ToString() : "Task aborted!";
MessageBox.Show(mes);
};
编辑:也是这一行:
metingProgress.Dispose();
可能会导致ObjectDisposed异常。如果后台进程仍在运行并尝试更新进度条,则您已经处理了该表单。您应该删除此行并将其留给垃圾收集器。