我用
RunWorkerAsync()
在 WinForms 中启动了后台工作者。该工作人员运行状态机并执行一些工作。我在表单上有一个“取消”按钮,该按钮应该停止工作人员;我用 CancelAsync()
来做这个。
问题是,我使用属性
IsBusy
在启动之前检查后台工作程序是否正在运行,但是,当调用 CancelAsync()
时,此属性仍然是 true
。因此,当我尝试重新启动工作程序时,它不会启动,因为逻辑认为它仍在运行。
在启动工作程序后,我尝试在 while 循环中使用
Application.DoEvents()
来保持表单响应,但这并没有解决问题。
我还尝试将
IsBusy
属性明确设置为 false,但据我了解,该属性是只读的。
据我目前的理解,只有在后台工作程序完成其操作后,
IsBusy
才会设置为 false,这意味着使用 CancelAsync()
不会将该属性设置为 false,因为从技术上讲,它并没有完成工作程序的操作。
有解决方法吗?还是我理解错误?
private void buttonStart_Click(object sender, EventArgs e)
{
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync();
buttonStart.Enabled = false;
}
}
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker)sender;
while (!worker.CancellationPending)
{
...
}
}
private void buttonCancel_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation && backgroundWorker1.IsBusy)
{
backgroundWorker1.CancelAsync();
buttonStart.Enabled = true;
}
}
BackgroundWorker
有一个 CancellationPending
属性,顾名思义,如果通过调用 true
方法发出取消信号,则返回 CancelAsync
。您可以将此属性与 IsBusy
结合使用来实现您想要的。
据我目前的理解,一旦后台工作者完成其操作,IsBusy 才会被设置为 false...
这是正确的。调用
CancelAsync()
本身不会将 IsBusy
设置为 false,这只能在工作进程完成其进程后才能完成。工作人员的完成被定义为 _DoWork()
函数到达终点。
因此,要取消该工作人员,我们只需在
e.cancel
时将 CancellationPending
设置为 true 即可。为此,需要更改 _DoWork()
函数中的逻辑。首先,需要更改 while
循环的条件,以便检查 CancellationPending
。
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker)sender;
while (someCondition)
{
if (worker.CancellationPending)
{
e.Cancel = true;
break;
}
...
}
}
通过调用
break
,应用程序退出主 while 循环,从而完成 _DoWork
函数。