Tutorial: Ejecutar una operación en segundo plano
Si tiene una operación que tarda mucho tiempo en completarse y no desea causar retrasos en la interfaz de usuario, puede utilizar la clase BackgroundWorker para ejecutar la operación en otro subproceso.
Para obtener una lista completa del código usado en este ejemplo, vea Procedimiento para ejecutar una operación en segundo plano.
Ejecución de una operación en segundo plano
Con el formulario activo en el Diseñador de Windows Forms de Visual Studio, arrastre dos controles Button desde el cuadro de herramientas al formulario y, después, establezca las propiedades
Name
y Text de los botones según la siguiente tabla.Botón Nombre Texto button1
startBtn
Iniciar button2
cancelBtn
Cancelar Abra el cuadro de herramientas, haga clic en la pestaña Componentes y, después, arrastre el componente BackgroundWorker al formulario.
El componente
backgroundWorker1
aparece en la bandeja de componentes.En la ventana Propiedades , establezca la propiedad WorkerSupportsCancellation en
true
.En la ventana Propiedades, haga clic en el botón Eventos y, después, haga doble clic en los eventos DoWork y RunWorkerCompleted para crear controladores de eventos.
Inserte su código —que requiere mucho tiempo— en el controlador de eventos DoWork.
Extraiga los parámetros requeridos por la operación de la propiedad Argument del parámetro DoWorkEventArgs.
Asigne el resultado del cálculo a la propiedad Result de DoWorkEventArgs.
Esto estará disponible para el controlador de eventos RunWorkerCompleted.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // Do not access the form's BackgroundWorker reference directly. // Instead, use the reference provided by the sender parameter. BackgroundWorker bw = sender as BackgroundWorker; // Extract the argument. int arg = (int)e.Argument; // Start the time-consuming operation. e.Result = TimeConsumingOperation(bw, arg); // If the operation was canceled by the user, // set the DoWorkEventArgs.Cancel property to true. if (bw.CancellationPending) { e.Cancel = true; } }
Private Sub backgroundWorker1_DoWork( _ sender As Object, e As DoWorkEventArgs) _ Handles backgroundWorker1.DoWork ' Do not access the form's BackgroundWorker reference directly. ' Instead, use the reference provided by the sender parameter. Dim bw As BackgroundWorker = CType( sender, BackgroundWorker ) ' Extract the argument. Dim arg As Integer = Fix(e.Argument) ' Start the time-consuming operation. e.Result = TimeConsumingOperation(bw, arg) ' If the operation was canceled by the user, ' set the DoWorkEventArgs.Cancel property to true. If bw.CancellationPending Then e.Cancel = True End If End Sub
Inserte código para recuperar el resultado de la operación en el controlador de eventos RunWorkerCompleted.
// This event handler demonstrates how to interpret // the outcome of the asynchronous operation implemented // in the DoWork event handler. private void backgroundWorker1_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled) { // The user canceled the operation. MessageBox.Show("Operation was canceled"); } else if (e.Error != null) { // There was an error during the operation. string msg = String.Format("An error occurred: {0}", e.Error.Message); MessageBox.Show(msg); } else { // The operation completed normally. string msg = String.Format("Result = {0}", e.Result); MessageBox.Show(msg); } }
' This event handler demonstrates how to interpret ' the outcome of the asynchronous operation implemented ' in the DoWork event handler. Private Sub backgroundWorker1_RunWorkerCompleted( _ sender As Object, e As RunWorkerCompletedEventArgs) _ Handles backgroundWorker1.RunWorkerCompleted If e.Cancelled Then ' The user canceled the operation. MessageBox.Show("Operation was canceled") ElseIf (e.Error IsNot Nothing) Then ' There was an error during the operation. Dim msg As String = String.Format("An error occurred: {0}", e.Error.Message) MessageBox.Show(msg) Else ' The operation completed normally. Dim msg As String = String.Format("Result = {0}", e.Result) MessageBox.Show(msg) End If End Sub
Implemente el método
TimeConsumingOperation
.// This method models an operation that may take a long time // to run. It can be cancelled, it can raise an exception, // or it can exit normally and return a result. These outcomes // are chosen randomly. private int TimeConsumingOperation( BackgroundWorker bw, int sleepPeriod ) { int result = 0; Random rand = new Random(); while (!bw.CancellationPending) { bool exit = false; switch (rand.Next(3)) { // Raise an exception. case 0: { throw new Exception("An error condition occurred."); break; } // Sleep for the number of milliseconds // specified by the sleepPeriod parameter. case 1: { Thread.Sleep(sleepPeriod); break; } // Exit and return normally. case 2: { result = 23; exit = true; break; } default: { break; } } if( exit ) { break; } } return result; }
' This method models an operation that may take a long time ' to run. It can be cancelled, it can raise an exception, ' or it can exit normally and return a result. These outcomes ' are chosen randomly. Private Function TimeConsumingOperation( _ bw As BackgroundWorker, _ sleepPeriod As Integer) As Integer Dim result As Integer = 0 Dim rand As New Random() While Not bw.CancellationPending Dim [exit] As Boolean = False Select Case rand.Next(3) ' Raise an exception. Case 0 Throw New Exception("An error condition occurred.") Exit While ' Sleep for the number of milliseconds ' specified by the sleepPeriod parameter. Case 1 Thread.Sleep(sleepPeriod) Exit While ' Exit and return normally. Case 2 result = 23 [exit] = True Exit While Case Else Exit While End Select If [exit] Then Exit While End If End While Return result End Function
En el Diseñador de Windows Forms, haga doble clic en
startButton
para crear el controlador de eventos Click.Llame al método RunWorkerAsync en el controlador de eventos Click para
startButton
.private void startBtn_Click(object sender, EventArgs e) { this.backgroundWorker1.RunWorkerAsync(2000); }
Private Sub startButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles startBtn.Click Me.backgroundWorker1.RunWorkerAsync(2000) End Sub
En el Diseñador de Windows Forms, haga doble clic en
startButton
para crear el controlador de eventos Click.Llame al método RunWorkerAsync en el controlador de eventos Click para
startButton
.private void cancelBtn_Click(object sender, EventArgs e) { this.backgroundWorker1.CancelAsync(); }
Private Sub cancelButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles cancelBtn.Click Me.backgroundWorker1.CancelAsync() End Sub
Importe los espacios de nombres System.ComponentModel y System.Threading al inicio del archivo.
using System; using System.ComponentModel; using System.Drawing; using System.Threading; using System.Windows.Forms;
Imports System.ComponentModel Imports System.Drawing Imports System.Threading Imports System.Windows.Forms
Presione F6 para compilar la solución y, a continuación, presione Ctrl+F5 para ejecutar la aplicación fuera del depurador.
Nota:
Si presiona F5 para ejecutar la aplicación en el depurador, el depurador detecta y muestra la excepción generada en el método
TimeConsumingOperation
. Cuando la aplicación se ejecuta fuera del depurador, BackgroundWorker controla la excepción y la almacena en caché en la propiedad Error de RunWorkerCompletedEventArgs.Haga clic en el botón Inicio para ejecutar una operación asincrónica y, después, haga clic en el botón Cancelar para detener una operación asincrónica en ejecución.
El resultado de cada operación se muestra en un elemento MessageBox.
Pasos siguientes
Implemente un formulario que informe del progreso de una operación asincrónica a medida que avanza. Para obtener más información, vea Procedimiento para implementar un formulario que usa una operación en segundo plano.
Implemente una clase que admita el patrón asincrónico para componentes. Para obtener más información, vea Implementación de un patrón asincrónico basado en eventos.
Vea también
.NET Desktop feedback