此BackgroundWorker当前正忙,无法同时运行多个任务

时间:2011-12-21 18:18:27

标签: c# wpf backgroundworker

我正在尝试在WPF应用程序中使用Background Worker。繁重的任务使用WebClient下载一些HTML并从中解析一些信息。理想情况下,我希望在不锁定UI的情况下进行下载和解析,并在完成工作后将结果放入UI中。

它工作正常,但是,如果我快速提交“下载和解析”命令,我会收到错误:

  

此BackgroundWorker当前正忙,无法运行多个任务   同时

所以我做了一些谷歌搜索,似乎我可以启用后台工作者的.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()!
}

6 个答案:

答案 0 :(得分:6)

调用CancelAsync仍然会触发RunWorkerCompleted事件。在这种情况下,您需要检查CancelAsync,确保未调用e.Cancelled。在此事件触发之前,您无法拨打RunWorkerAsync

或者,我建议您按照Tigran的建议做,并每次创建一个新的BackgroundWorker

此外,我建议将_backgroundWorker_DoWork的结果存储在e.Result中,然后在_backgroundWorker_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()!
}

答案 1 :(得分:5)

问题在于CancelAsync()做了什么:以异步方式取消。这意味着它不会立即停止 ,但过了一段时间。那段时间永远无法计算或预测,所以你有几个选择:

  1. 等到这个backround worker停止真的,等待一段时间,直到它的IsBusy属性变为false

  2. 或者,我认为,更好的解决方案是启动另一个background worker,考虑到取消请求已经发送到第一个,因此它将很快或稍后停止。在这种情况下,您需要知道来自哪个 background worker数据,以便处理它,在第二个数据开始时,第一个数据仍将运行并从{ {1}}。

  3. 希望这有帮助。

答案 2 :(得分:2)

CancelAsync在工作人员取消并停止工作之前返回。因此,您的RunWorkerAsync调用将在工作人员准备好之前启动,并且您将收到该错误。你需要等待工人先做好准备。

答案 3 :(得分:0)

当我对跟踪异步操作的进度不感兴趣时​​,我更倾向于只在ThreadPool.QueueUserWorkItem打一个lambda,而不是实例化并设置一个后台工作器,我必须检查状态为能够以理智的方式重用。

答案 4 :(得分:0)

你需要在开始之前进行验证。

f( !bw.IsBusy )
    bw.RunWorkerAsync();
else
    MessageBox.Show("Can't run the bw twice!");

答案 5 :(得分:0)

您正在调用CancelAsync而不等待后台工作程序实际取消该工作。此外,您必须拥有自己的逻辑来取消工作。 MSDN上有一个很好的例子,展示了如何做到这一点。基本上在你的parseanddownloadresult()方法中,你需要检查CancellationPending属性。