如何在窗体关闭事件中停止BackgroundWorker?

75

我有一个表单,会启动一个BackgroundWorker,该worker应该更新表单自己的文本框(在主线程上),因此需要调用Invoke((Action) (...));
如果我在HandleClosingEvent中只是执行bgWorker.CancelAsync(),那么当我调用Invoke(...)时会出现ObjectDisposedException异常,这很容易理解。但如果我等待bgWorker完成,那么.Invoke(...)将永远不会返回,这也很容易理解。

有什么办法可以关闭这个应用程序而不出现异常或死锁吗?

以下是Form1类的3个相关方法:

    public Form1() {
        InitializeComponent();
        Closing += HandleClosingEvent;
        this.bgWorker.RunWorkerAsync();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
        while (!this.bgWorker.CancellationPending) {
            Invoke((Action) (() => { this.textBox1.Text = Environment.TickCount.ToString(); }));
        }
    }

    private void HandleClosingEvent(object sender, CancelEventArgs e) {
        this.bgWorker.CancelAsync();
        /////// while (this.bgWorker.CancellationPending) {} // deadlock
    }

你尝试过使用BeginInvoke而不是Invoke吗?这样你就不必等待invokemessage返回了。 - Mez
是的。没有死锁,但我不知道BeginInvoke何时被处理(在主线程上),所以我又回到了ObjectDisposed异常。 - THX-1138
12个回答

-2

另一种方式:

if (backgroundWorker.IsBusy)
{
    backgroundWorker.CancelAsync();
    while (backgroundWorker.IsBusy)
    {
        Application.DoEvents();
    }
}

-2
一个可行的解决方案,但过于复杂。思路是生成一个计时器,该计时器将不断尝试关闭窗体,直到所述bgWorker已死亡,窗体才会拒绝关闭。
private void HandleClosingEvent(object sender, CancelEventArgs e) {
    if (!this.bgWorker.IsBusy) {
        // bgWorker is dead, let Closing event proceed.
        e.Cancel = false;
        return;
    }
    if (!this.bgWorker.CancellationPending) {
        // it is first call to Closing, cancel the bgWorker.
        this.bgWorker.CancelAsync();
        this.timer1.Enabled = true;
    }
    // either this is first attempt to close the form, or bgWorker isn't dead.
    e.Cancel = true;
}

private void timer1_Tick(object sender, EventArgs e) {
    Trace.WriteLine("Trying to close...");
    Close();
}

这听起来对我来说非常不专业。我不会这样做。 - Marc

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