C# 此BackgroundWorker当前正忙,无法同时运行多个任务
我试图在WPF应用程序中使用后台工作程序。繁重的任务使用WebClient下载一些HTML并解析其中的一些信息。理想情况下,我希望在下载和解析时不锁定UI,并在UI工作完成后将结果放入UI中 但是,如果我快速提交“下载并解析”命令,就会出现错误: 此BackgroundWorker当前正忙,无法运行多个任务 同时 所以我在谷歌上搜索了一下,似乎我可以启用后台工作程序的C# 此BackgroundWorker当前正忙,无法同时运行多个任务,c#,wpf,backgroundworker,C#,Wpf,Backgroundworker,我试图在WPF应用程序中使用后台工作程序。繁重的任务使用WebClient下载一些HTML并解析其中的一些信息。理想情况下,我希望在下载和解析时不锁定UI,并在UI工作完成后将结果放入UI中 但是,如果我快速提交“下载并解析”命令,就会出现错误: 此BackgroundWorker当前正忙,无法运行多个任务 同时 所以我在谷歌上搜索了一下,似乎我可以启用后台工作程序的.WorkerSupportsCancellation属性,只需.CancelAsync()。但是,这并没有按预期工作(取消当前的
.WorkerSupportsCancellation
属性,只需.CancelAsync()
。但是,这并没有按预期工作(取消当前的下载和解析)
我仍然得到上面的错误
这是我的密码:
//In window constructor.
_backgroundWorker.WorkerSupportsCancellation = true;
_backgroundWorker.DoWork += new DoWorkEventHandler(_backgroundWorker_DoWork);
_backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted);
//Declared at class level variable.
BackgroundWorker _backgroundWorker = new BackgroundWorker();
//This is the method I call from my UI.
private void LoadHtmlAndParse(string foobar)
{
//Cancel whatever it is you're doing!
_backgroundWorker.CancelAsync();
//And start doing this immediately!
_backgroundWorker.RunWorkerAsync(foobar);
}
POCOClassFoo foo = new POCOClassFoo();
void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//This automagically sets the UI to the data.
Foo.DataContext = foo;
}
void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
//DOING THE HEAVY LIFTING HERE!
foo = parseanddownloadresult()!
}
当我对跟踪异步操作的进度不感兴趣时,我倾向于只在
线程池.QueueUserWorkItem
上打一个lambda,而不是实例化和设置一个后台工作程序,我必须检查它的状态才能正常重用。在工作程序取消并停止其工作之前,CancelAsync返回。因此,您的RunWorkerAsync调用是在工作程序准备就绪之前启动的,您将收到该错误。您需要先等待工作人员准备就绪。您需要在开始工作之前进行验证
f( !bw.IsBusy )
bw.RunWorkerAsync();
else
MessageBox.Show("Can't run the bw twice!");
问题是,
CancelAsync()
做它想做的事情:以异步方式取消。这意味着它不会立即停止,而是在一段时间后停止。时间永远无法计算或预测,因此您有两个选择:
false,等待该反向工作者
真正停止
后台工作人员
,考虑到取消请求已经发送到第一个,所以它将很快或稍后停止。在这种情况下,您需要知道数据来自哪个后台工作者,以便处理它或不处理它,因为在第二个开始时,第一个后台工作者仍将运行,并从WebService
泵送数据
希望这有帮助。您正在调用CancelAsync,而无需等待后台工作人员实际取消工作。此外,你必须有自己的逻辑来取消工作。有一个很好的例子说明了如何做到这一点。基本上,在parseanddownloadresult()方法中,您需要检查属性。调用
CancelAsync
仍将触发RunWorkerCompleted
事件。在这种情况下,您需要通过检查e.Cancelled
,确保未调用CancelAsync
。在触发此事件之前,您无法调用RunWorkerAsync
或者,我建议您按照Tigran的建议做,每次创建一个新的BackgroundWorker
此外,我建议将\u backgroundWorker\u DoWork
的结果存储在e.Result
中,然后从\u backgroundWorker\u RunWorkerCompleted
中的相同位置检索它们
也许是这样的
BackgroundWorker _backgroundWorker;
private BackgroundWorker CreateBackgroundWorker()
{
var bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += _backgroundWorker_DoWork;
bw.RunWorkerCompleted += new _backgroundWorker_RunWorkerCompleted;
return bw.
}
private void LoadHtmlAndParse(string foobar)
{
//Cancel whatever it is you're doing!
if (_backgroundWorer != null)
{
_backgroundWorker.CancelAsync();
}
_backgroundWorker = CreateBackgroundWorker();
//And start doing this immediately!
_backgroundWorker.RunWorkerAsync(foobar);
}
//you no longer need this because the value is being stored in e.Result
//POCOClassFoo foo = new POCOClassFoo();
private void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
//Error handling goes here.
}
else
{
if (e.Cancelled)
{
//handle cancels here.
}
{
//This automagically sets the UI to the data.
Foo.DataContext = (POCOClassFoo)e.Result;
}
}
private void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
//DOING THE HEAVY LIFTING HERE!
e.Result = parseanddownloadresult()!
}
这将导致长串的模式消息框,用户无法从中逃脱。