You are on page 1of 4

Backgroundworker en C#

Productividad y eficiencia desarrollando en .NET


Nota: Ejemplo completo de uso del control BackgroundWorker. El artculo inicial se cre en ingls y
fue publicado aqu. En vista del xito que ha tenido lo traduzco al castellano y lo republico tambin
en este apartado.
Introduccin

El control BackgroundWorker fue introducido en el .NET Framework 2.0 y permite realizar


operaciones costosas o duraderas en un hilo diferente al del interfaz, de manera que la aplicacin
sigue respondiendo al usuario mientras este trabajo se procesa en segundo plano.

Usando este control, la gestin de hilos est encapsulada en el control de manera que el
programador no tiene que lidiar con hilos (threads), invokes o delegados (delegates).
Ejemplo

Este sencillo ejemplo cubre prcticamente todas las posibilidades de este componente: soporte de
cancelacin, gestin de errores , informacin de progreso (y ejemplo de como pasar informacin en
cada notificacin de progreso)

Evento backgroundWorker1_DoWork

El evento backgroundWorker1_DoWork es desencadenado por el control cuando

el mtodo RunWorkerAsync()es invocado. Este mtodo se ejecuta en un


segundo hilo que crea el control BackgroundWorker. Al no ser el hilo
principal del interfaz, no intentes acceder a ningn control aqu, o si lo
haces utiliza para ello un delegado.
01 //[System.Diagnostics.DebuggerNonUserCodeAttribute()] (*)
02 private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
03 {
//no usaremos cdigo try/catch aqu, a no ser que despus hagamos
04
un throw de la excepcin capturada.
//es necesario dejar que el backgroundworker sea quien capture
05
cualquier excepcin producida.
//si se produce una excepcin, el control la disponibilizar una
06
vez haya finalizado su ejecucin,
07
//y disparado el evento "backgroundWorker1_RunWorkerCompleted"
//the RunWorkerCompletedEventArgs object, method
08
backgroundWorker1_RunWorkerCompleted
09
//try
10
//{
11
DateTime start = DateTime.Now;
12
e.Result = "";
13
for (int i = 0; i < 100; i++)
14
{
15
System.Threading.Thread.Sleep(50); //simulamos trabajo
16
//hemos completado un porcentaje del trabajo previsto,
17
luego notificamos de ello.
18
backgroundWorker1.ReportProgress(i, DateTime.Now);
19
//descomenta este cdigo para ver como esta excepcin es
20
gestionada por el
21
//control backgroundworker
//descomenta tambin el atributo indicado arriba para
22
evitar que el depurador
23
//pare en la excepcin, ya que queremos simular
24
//el comportamiento del control en tiempo de ejecucin.
25
//if (i == 34)
26
//
throw new Exception("something wrong here!!");
27
//en caso de que soporte cancelacin y el control haya
28
recibido la peticin de cancelacin,
//cancelamos el trabajo. Es la manera en la que realizamos
29
una salida "limpia".
30
if (backgroundWorker1.CancellationPending)
31
{
32
e.Cancel = true;
33
return;
34
}
35
}
36

37
38

TimeSpan duration = DateTime.Now - start;

//aqu podramos devolver informacin de utilidad, como el


resultado de un clculo,
//nmero de elementos afectados, etc.. de manera sencilla y
40
segura
41
//al hilo principal
39

42
43
44
45
46
47

e.Result = "Duration: " + duration.TotalMilliseconds.ToString()


+ " ms.";
//}
//catch(Exception ex){
//
MessageBox.Show("Don't use try catch here!");
//}
}

(*) Nota: El atributo [System.Diagnostics.DebuggerNonUserCodeAttribute()] es necesario para


evitar que el depurador interrumpa el flujo de la ejecucin en caso de que una excepcin se
produzca. De esta manera podemos trabajar en modo depuracin con el mismo comportamiento
que el control tendra en modo ejecucin. Este comportamiento consistira en capturar
internamente la excepcin (por eso no usaremos try/catch en el mtodo) y devolvernos la misma
junto con el resultado, en el mtodo backgroundWorker1_RunWorkerCompleted
Evento backgroundWorker1_ProgressChanged

Este evento es lanzado en el hilo principal, por lo que aqu SI podemos acceder a controles del
formulario de manera segura.
01 private void backgroundWorker1_ProgressChanged(object sender,
02 ProgressChangedEventArgs e)
03 {
progressBar1.Value = e.ProgressPercentage; //actualizamos la barra
04
de progreso
DateTime time = Convert.ToDateTime(e.UserState); //obtenemos
05
informacin adicional si procede
06
07
//en este ejemplo, logamos a un textbox
08
txtOutput.AppendText(time.ToLongTimeString());
09
txtOutput.AppendText(Environment.NewLine);
10 }
Evento backgroundWorker1_RunWorkerCompleted

Este mtodo se ejecuta cuando la tarea ha sido finalizada. Una tarea se finaliza cuando:
a) termina de manera normal
b) termina con error
c) es cancelada.

En el objeto de tipo RunWorkerCompletedEventArgs encontraremos informacin detallada del tipo


de finalizacin, as como los datos que hemos podido pasar en la propiedad Result.
01 private void backgroundWorker1_RunWorkerCompleted(object sender,
02 RunWorkerCompletedEventArgs e)
03
{
04
if (e.Cancelled) {
05
MessageBox.Show("The task has been cancelled");
06
}
07
else if (e.Error != null)
08
{
MessageBox.Show("Error. Details: " +
(e.Error as Exception).ToString());
10
}
11
else {
09

MessageBox.Show("The task has been completed. Results: " +


e.Result.ToString());
13
}
14
}
12

Enviado las rdenes de inicio y cancelacin al control


Notificamos al control backgroundworker de que cancele el proceso.
1 private void btoCancel_Click(object sender, EventArgs e)
2 {
//este cdigo no mata ni afecta al hilo en el que se est ejecutando
3
el procesamiento.
4
//Sirve a efectos de notificacin, que debe de ser
5
//gestionada de la manera que se indica arriba en el ejemplo
6
backgroundWorker1.CancelAsync();
7
}
Lanzamos el trabajo. En este momento, el control backgroundworker lanza un hilo en el
que ejecuta la tarea asignada, a travs del mtodo backgroundWorker1_DoWork visto
anteriormente.
1 private void btoStart_Click(object sender, EventArgs e)
2 {
3 backgroundWorker1.RunWorkerAsync();
4 }

You might also like