Muchas veces en nuestras aplicaciones necesitamos realizar tareas largas que deben ser ejecutados en un thread separado, pero al mismo tiempo mostrar al usuario una barra de progreso o cualquier tipo de notificación para que el usuario sienta que la aplicación no ha dejado de funcionar sino que esta ejecutando una tarea larga y que además puede abortar esa tarea.
Para ello utilizaremos la clase BackgroundWorker, La clase BackgroundWorker permite ejecutar una operación en un subproceso dedicado e independiente, pudiendo el usuario interactuar con la interfaz de usuario mientras se ejecuta la tarea.
Para lanzar una tarea en otro thread utilizaremos el evento DoWork de la clase BackgroundWorker, el código en el event handler del evento DoWork se jecutara en un thread diferente
int maxRecords = 1000; BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += delegate(object s, DoWorkEventArgs args) { for (int x = 1; x < maxRecords; x++) { System.Threading.Thread.Sleep(10); } }; worker.RunWorkerAsync();
De esta manera lanzaremos en otro Thread totalmente diferentes el recorrido de los registros
Si queremos pasar parámetros a la tarea , nosotros podemos pasar esos parámetros al método RunWorkerAsync a través de la propiedad Argument del evento DoWork
BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += delegate(object s, DoWorkEventArgs args) { string path = (string)args.Argument; //hacer algo }; worker.RunWorkerAsync("c:\myFile.txt");
Si queremos retornar un valor como el resultado de un calculo, debemos retornar ese valor a través de la propiedad Result de DoWorkEventArgs en el event handler de DoWork. Este valor será recogido por nosotros en el evento RunWorkerCompleted al que tenemos que suscribirnos
BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += delegate(object s, DoWorkEventArgs args) { args.Result = CalculationMethod(); }; worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args) { object result = args.Result; }; worker.RunWorkerAsync();
Si queremos cancelar el proceso mientras se esta ejecutando debemos de poner la propiedad WorkerSupportsCancellation a True, de esta manera podemos llamar al metodo CancelAsync para que cancele el proceso. Este método pone la propiedad CancellationPending a true y en ele evnt handler DoWork deberemos comprobarla para abortar el proceso poniendo la propiedad Cancel a true
for (int x = 1; x < maxRecords; x++) { //check if there is a cancelat if (worker.CancellationPending) { args.Cancel = true; return; } System.Threading.Thread.Sleep(10); } }; worker.RunWorkerAsync();
Si queremos notificar el progreso al usuario a través de la interfaz de usuario, debemos poner primero la propiedad WorkerReportsProgess a true, suscribirnos al evento ProgressChanged que se lanzara por cada cambio de progreso que nosotros notifiquemos en el event handler DoWork a través del método ReportProgress
int maxRecords = 1000; BackgroundWorker worker = new BackgroundWorker(); worker.WorkerReportsProgress = true; worker.DoWork += delegate(object s, DoWorkEventArgs args) { for (int x = 1; x < maxRecords; x++) { System.Threading.Thread.Sleep(10); worker.ReportProgress(Convert.ToInt32(((decimal)x / (decimal)maxRecords) * 100)); } }; worker.ProgressChanged += delegate(object s, ProgressChangedEventArgs args) { int percentage = args.ProgressPercentage; }; worker.RunWorkerAsync();
Si queremos notificar este porcentaje al usuario necesitamos utilizar la clase Dispatcher que nos permite comunicarnos con otro Thread , si queremos coger la referencia de un objeto de la interfaz de usuario como un botón para habilitarlo o deshabilitarlo lo tenemos que referenciar
System.Windows.Threading.Dispatcher aDisp = Button1.Dispatcher;
Aquí os dejo un ejemplo de como utilizarlo todo junto para que podáis jugar con ello
Muchas veces en nuestras aplicaciones necesitamos realizar tareas largas que deben ser ejecutados en
Buenisima explicación y ejemplo. Enhorabuena Oskar
Muy buen artículo, lo apunto.