2010-02-20 18 views
8

In un'app WPF dispongo di un'attività di accesso al database interrotta, eseguita periodicamente da un timer e questa attività è stata eseguita in un thread di BackgroundWorker.Come gestire le eccezioni da un thread di BackgroundWorker?

In caso di tentativo di connessione non riuscito sollevare un'eccezione tramite la costruzione try_catch e voglio aggiornare un testo della barra di stato in un thread dell'interfaccia utente.

C'è qualche pre-evento di costruzione di eventi in un BackgroundWorker per l'implementazione di questo, qualcosa come DoWorkEventHandler o RunWorkerCompletedEventHandler, che può essere utilizzato per questo? Se no, come si fa meglio?

Edited (aggiunta):

Se voglio gestire l'eccezione all'interno RunWorkerCompletedEventHandler, utilizzando e.Error parametro, non funziona. In caso di eccezioni non gestite nel thread BackgroundWorker, l'applicazione si blocca e il debugger punta alla stringa di codice che viene inserita all'interno del thread BackgroundWorker, dicendo che: L'eccezione non è stata gestita dal codice utente.

Quindi, in questo caso, il thread non si ferma solo, segnalando allo RunWorkerCompletedEventHandler che si è arrestato con errore, ma l'intera applicazione smette di funzionare.

+0

Grazie a tutti per la risposta! Tenendo conto di alcune risposte, ho aggiornato la mia domanda con maggiori dettagli. – rem

risposta

5

Un'interfaccia utente WPF può essere aggiornata da un thread in background utilizzando Dispatcher.BeginInvoke.

Per esempio se il codice di fondo faceva parte di una finestra, allora si potrebbe aggiornare un TextBlock:

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

Edit:

Se il codice di fondo erano in una classe diversa da quella finestra si potrebbe fare un'interfaccia per aiutare:

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

implementare l'interfaccia nella finestra

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

Nella classe con l'operatore in background, creare una proprietà per contenere un riferimento all'interfaccia.

public IShowStatus StatusDisplay { get; set; } 

Nella classe Window inizializzare la classe dello sfondo.

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

Infine nel tuo thread in background si può dire:

StatusDisplay.ShowStatus("Connection Failed!"); 
+0

Nel mio caso il codice dello sfondo non fa parte di una finestra ma viene eseguito all'interno di una classe separata. Inoltre, l'eccezione ha luogo in un metodo statico. Quindi, questa parola chiave non è valida in questo caso. Per favore, aiutami a capire come potrei fare riferimento alla mia finestra principale dell'interfaccia utente in questo caso? – rem

+0

Ho aggiunto delle note in risposta alla tua domanda. –

6

Il RunWorkerCompletedEventArgs e dello RunWorkerCompletedEventHandler contiene la proprietà Error è di tipo Eccezione. Se non si sono verificate eccezioni durante il lavoro del thread in background, il prpery ha valore null. Altrimenti contiene l'errore che si è verificato.

3
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    Exception exceptionThrowDuringDoWorkEventHandler = e.Error; 
} 
+0

Quando provo a generare un'eccezione dal thread di BackgroundWorker, l'app si blocca con: L'eccezione non è stata gestita dal codice utente. Non arrivo mai a bw_RunWorkerCompleted. Mi sto perdendo qualcosa? – Doug

3

Impostare la WorkerReportsProgress di proprietà del lavoratore sfondo per vero, quindi aggiungere un gestore di eventi per l'evento ProgressChanged.Nel codice seguente, ho aggiunto anche un gestore di eventi per Form.Load.

Ora provare il seguente codice:

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(); 
     } 
Problemi correlati