当BackgroundWorker在传递给DoWork之前完成时,我能得到DoWorkEventArgs吗?

本文关键字:DoWorkEventArgs 完成时 BackgroundWorker DoWork | 更新日期: 2023-09-27 18:12:40

我正试图修补现有GUI中的问题,其中大部分是通过从这个答案粘贴到下面的代码解决的->如何等待BackgroundWorker取消?

private BackgroundWorker worker = new BackgroundWorker();
private AutoResetEvent _resetEvent = new AutoResetEvent(false);
public Form1()
{
    InitializeComponent();
    worker.DoWork += worker_DoWork;
}
public void Cancel()
{
    worker.CancelAsync();
    _resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
    // IS THERE ANY WAY TO TELL IF THE BACKGROUNDWORKER STOPPED DUE TO e.Cancel here???
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
    while(!e.Cancel)
    {
        // do something
    }
    _resetEvent.Set(); // signal that worker is done
}

我的问题作为注释添加到Cancel函数的末尾。现在有没有办法知道为什么后台工作人员关闭了?

当BackgroundWorker在传递给DoWork之前完成时,我能得到DoWorkEventArgs吗?

有很多选择。你可能可以检查CancellationPending & help;我不记得当DoWork处理程序返回—我对此表示怀疑,但如果是这样的话,你就会在等待和处理者之间进行一场赛跑。(我本来只是测试它自己,但你的问题不包括一个很好的最小,完整和可验证的代码示例,我没有麻烦自己创建一个。)

另一种方法是使用TaskCompletionSource<T>代替AutoResetEvent,它支持补全/取消语义:

private BackgroundWorker worker = new BackgroundWorker();
private TaskCompletionSource<object> _tcs;
public Form1()
{
    InitializeComponent();
    worker.DoWork += worker_DoWork;
    // Need to reinitialize when you actually start the worker...you
    // didn't show that code, so I'm putting it here
    _tcs = new TaskCompletionSource<object>();
}
public async Task Cancel()
{
    worker.CancelAsync();
    try
    {
        await _tcs.Task;
        // you'll be here if the task completed normally
    }
    catch (TaskCancelledException)
    {
        // you'll be here if the task was cancelled
    }
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
    while(!e.CancellationPending)
    {
        // do something
    }
    if (e.CancellationPending)
    {
        _tcs.SetCanceled();
    }
    else
    {
        // if you actually want to return a value, you can set whatever
        // value you want here. You can also use the correct type T for
        // the TaskCompletionSource<T> declaration.
        _tcs.SetResult(null);
    }
}

如果你愿意,你可以把Cancel()调用为Cancel().Wait(),但如果你能在那里使用await就更好了,这样你就可以避免阻塞线程。

比这更好的是从BackgroundWorker切换到TaskCancellationTokenSource。然后,您等待的东西可以是任务本身,而不是任务的代理。