简体   繁体   English

当BackgroundWorker完成传递给DoWork之前,我可以得到DoWorkEventArgs吗?

[英]Can I get DoWorkEventArgs when BackgroundWorker completes before it's passed to DoWork?

I am trying to patch a problem in an existing GUI, most of which was solved by the code pasted below from this answer -> How to wait for a BackgroundWorker to cancel? 我正在尝试修补现有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
}

My question is added as a comment to the end of the Cancel function. 我的问题已作为注释添加到“取消”功能的末尾。 Is there any way to know at this point why the backgroundworker shut down? 在这一点上有什么方法可以知道为什么后台工作人员关闭了吗?

There are lots of options. 有很多选择。 You probably can check CancellationPending …I don't recall if that gets reset when the DoWork handler returns — I doubt it, but if it does you'd wind up with a race between your wait and the handler returning. 您可能可以检查CancellationPending …我不记得DoWork处理程序返回时是否重置了该设置—我对此表示怀疑,但是如果这样做了,您最终会在等待和处理程序返回之间陷入竞争。 (I would've just tested it myself, but your question doesn't include a good Minimal, Complete, and Verifiable code example and I didn't trouble myself to create one.) (我本人将自己对其进行测试,但是您的问题不包括一个很好的“ 最小,完整和可验证”代码示例,并且我没有麻烦自己创建一个。)

Another way is to, instead of AutoResetEvent , use TaskCompletionSource<T> , which supports completion/cancellation semantics: 另一种方法是使用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);
    }
}

You can call Cancel() as Cancel().Wait() if you want, but it's even better if you can use await there, so you can avoid blocking a thread. 您可以根据需要将Cancel()称为Cancel().Wait() ,但最好await此处使用await更好,因此可以避免阻塞线程。

Even better than that is to switch from BackgroundWorker to Task and CancellationTokenSource . 更好的是从BackgroundWorker切换到TaskCancellationTokenSource Then the thing you wait on can be the task itself, instead of a proxy for the task. 然后,您等待的内容可以是任务本身,而不是任务的代理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM