我可以在BackgroundWorker的RunWorkerCompleted()方法中调用RunWorkerAsync()吗?

3
我有一个后台工作程序已经设置好了。在完成后,我希望可以重新启动它。也就是说,如果DoWork()没有成功,我想要在RunWorkerCompleted()处理程序中再次调用RunWorkerAsync()。我能确保IsBusy=false在我进入RunWorkerCompleted()时吗?
例如:
void myThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if ((e.Error == null) && !e.Cancelled && (bool)e.Result)
        // do stuff
    else
        myThread.RunWorkerAsync();
}

我似乎找不到任何关于这种行为的确认。

1
Hans Passant在这里(https://social.msdn.microsoft.com/Forums/vstudio/en-US/ad9a9a02-8a11-4bb8-b50a-613bcaa46886/backgroundworkerisbusy-question)的回答是相当好的确认。 - Michael Repucci
有趣。不过这很有道理,你不想在后台线程上更改可能与UI相关的属性。 - Jonathan Allen
没错。虽然从这里引用的文档(https://dev59.com/NHE85IYBdhLWcg3wYSZk#2806824)看来,RunWorkerCompleted()将在UI线程上被调用,因此允许在其中执行此类操作。但我不确定IsBusy是否已经被设置为false,或者是否会一直保持true,直到RunWorkerCompleted()完成。 - Michael Repucci
你发布的代码有问题,如果e.Error != null,则不能假设e.Result的任何内容。而且最好想出一种与UI交锁的方案,在用户关闭窗口时很少需要重新启动BGW,或者在BGW处于活动状态时关闭窗口。除此之外,再次调用RunWorkerAsync()没有问题。 - Hans Passant
哦,糟糕。我的意思是 e.Error == null。我会编辑的。谢谢! - Michael Repucci
2个回答

1

不幸的是,文档对这个问题没有明确的说明。此外,IsBusy 属性的代码示例实际上非常糟糕,因为它在属性上自旋等待并在循环中调用 Application.DoEvents()

话虽如此,正如其他人建议的那样,最明智的设计是只有当异步工作者实际运行时标志才为 true。即当 DoWork 事件处理程序返回时,它应该被设置回 false。实际上,如果查看 实现, 就会发现这一点:

private void AsyncOperationCompleted(object arg)
{
    isRunning = false;
    cancellationPending = false;
    OnRunWorkerCompleted((RunWorkerCompletedEventArgs)arg);
}

public bool IsBusy
{
    get
    {
        return isRunning;
    }
}

这里的isRunning标志是IsBusy属性返回的内容,也是RunWorkerAsync()用来检查异常是否应该抛出的内容。正如在这里所看到的,实现在触发RunWorkerCompleted事件之前将其设置回false

因此,是的...从RunWorkerCompleted事件处理程序调用RunWorkerAsync()是完全安全的。

如果没有记录这一点,实现可能会改变,但在这个阶段,如果发生这种情况,我会非常惊讶。特别是在代码开源的情况下,实现成为行为规范的一部分。


非常好的回答。感谢提供源链接。我之前不知道这个资源存在! - Michael Repucci

1
我不认为有任何理由不这样做。按照定义,操作已完成,因此IsBusy应该始终为false。你又回到了你应该在的UI线程上。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接