Как остановить BackgroundWorker на закрытии формы? - PullRequest
66 голосов
/ 13 ноября 2009

У меня есть форма, которая порождает BackgroundWorker, который должен обновить собственное текстовое поле формы (в главном потоке), следовательно, Invoke((Action) (...)); call.
Если в HandleClosingEvent я просто делаю bgWorker.CancelAsync(), тогда я получаю ObjectDisposedException на Invoke(...) звонке, понятно. Но если я сижу в HandleClosingEvent и жду выполнения bgWorker, то .Invoke (...) никогда не возвращается, также понятно.

Есть идеи, как закрыть это приложение, не получив исключение или тупик?

Ниже приведены 3 соответствующих метода простого класса Form1:

    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
    }

Ответы [ 12 ]

0 голосов
/ 13 ноября 2009

Я передаю SynchronizationContext, связанный с текстовым полем, в BackgroundWorker и использую его для обновления в потоке пользовательского интерфейса. Используя SynchronizationContext.Post, вы можете проверить, удаляется или удаляется элемент управления.

0 голосов
/ 13 ноября 2009

Одно решение, которое работает, но слишком сложно. Идея состоит в том, чтобы вызвать таймер, который будет продолжать пытаться закрыть форму, и форма будет отказываться закрываться до тех пор, пока 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();
}
...