Как обрабатывать исключения из потока BackgroundWorker? - PullRequest
8 голосов
/ 20 февраля 2010

В приложении WPF у меня есть запланированная задача доступа к базе данных, периодически запускаемая таймером, и эта задача выполнялась в потоке BackgroundWorker.

Когда попытка подключения не удалась, я возбуждаю исключение конструкцией try_catch и хочу обновить текст строки состояния в потоке пользовательского интерфейса.

Есть ли в BackgroundWorker какая-то предварительная конструкция события для реализации этого, что-то вроде DoWorkEventHandler или RunWorkerCompletedEventHandler, которое можно использовать для этого? Если нет, то как это сделать лучше?

Отредактировано (добавлено):

Если я хочу обработать исключение внутри RunWorkerCompletedEventHandler, используя параметр e.Error, это не сработает. В случае, если я оставляю исключение необработанным в потоке BackgroundWorker, приложение зависает, и отладчик указывает на строку кода, которая выполняется в потоке BackgroundWorker, говоря, что: Исключение не было обработано кодом пользователя .

Таким образом, в этом случае поток не просто останавливается, сообщая RunWorkerCompletedEventHandler, что он остановился с ошибкой, но все приложение перестает работать.

Ответы [ 5 ]

6 голосов
/ 20 февраля 2010

RunWorkerCompletedEventArgs e из RunWorkerCompletedEventHandler содержит свойство Error, которое имеет тип Исключение. Если во время работы фонового потока не возникло исключений, значение имеет значение null. Иначе он содержит ошибку, которая произошла.

5 голосов
/ 20 февраля 2010

Пользовательский интерфейс WPF можно обновить из фонового потока с помощью Dispatcher.BeginInvoke.

Например, если ваш фоновый код был частью окна, вы можете обновить TextBlock:

this.Dispatcher.BeginInvoke((Action)(() =>
    {
        textBlock.Text = "Connection Failed!";
    }));

Редактировать:

Если ваш фоновый код был в классе, отличном от вашего Window, вы могли бы сделать интерфейс, чтобы помочь:

public interface IShowStatus
{
    void ShowStatus(string message);
}

Реализация интерфейса в вашем Window

public void ShowStatus(string message)
{
   this.Dispatcher.BeginInvoke((Action)(() =>
       {
           textBlock.Text = message;
       }));
}

В вашем классе с фоновым рабочим создайте свойство для хранения ссылки на интерфейс.

public IShowStatus StatusDisplay { get; set; }

В вашем классе Window инициализируйте класс фона.

public void InitBackground()
{
    BackgroundClass background = new BackgroundClass();
    background.StatusDisplay = this;
    ...

Наконецв вашей фоновой ветке вы можете сказать:

StatusDisplay.ShowStatus("Connection Failed!");
3 голосов
/ 20 февраля 2010

Установите для свойства WorkerReportsProgress фонового работника значение true , затем добавьте обработчик события для события ProgressChanged . В следующем коде я также добавил обработчик событий для Form.Load.

Теперь попробуйте следующий код:

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            MessageBox.Show(e.UserState.ToString());
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                //some code that throws an exception
                throw new NotImplementedException();
            }
            catch (Exception ex) 
            {
                backgroundWorker1.ReportProgress(0/*percent of progress*/, ex);

            }
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();
        }
3 голосов
/ 20 февраля 2010
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
     Exception exceptionThrowDuringDoWorkEventHandler = e.Error;
}
0 голосов
/ 09 мая 2018

Если я хочу обработать исключение внутри RunWorkerCompletedEventHandler, используя параметр e.Error, это не работает В случае, если я оставлю исключение в BackgroundWorker поток, приложение зависает и отладчик указывает на строка кода, которая выполняется в потоке BackgroundWorker, говоря, что: Исключение не было обработано кодом пользователя .

Итак, в этом случае поток не просто останавливается, сигнализируя RunWorkerCompletedEventHandler что он остановился с ошибкой, но все приложение перестало работать.

Мне очень любопытно по этому поводу. Попробуйте запустить следующий код в консольном приложении и посмотрите, происходит ли сбой вашей программы или ошибка появляется в RunWorkerCompletedEventArgs.

    static void Main(string[] args)
    {
        var bw = new BackgroundWorker();
        bw.DoWork += Bw_DoWork;
        bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
        bw.RunWorkerAsync();

        Console.ReadKey();
    }

    private static void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        Console.WriteLine("Complete.");
        Console.WriteLine(e.Error);
    }

    private static void Bw_DoWork(object sender, DoWorkEventArgs e)
    {
        throw new NotImplementedException();
    }
...