Tutorial: Ejecutar una operación en segundo plano

Actualización: noviembre 2007

Si tiene una operación que llevará mucho tiempo completarse y no desea que provoque demoras 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 utilizado en este ejemplo, vea Cómo: Ejecutar una operación en segundo plano.

Nota:

Los cuadros de diálogo y comandos de menú que se ven pueden diferir de los descritos en la Ayuda, en función de la configuración activa o la edición. Para cambiar la configuración, elija la opción Importar y exportar configuraciones en el menú Herramientas. Para obtener más información, vea Valores de configuración de Visual Studio.

Para ejecutar en segundo plano una operación

  1. Con el formulario activo en el Diseñador de Windows Forms, arrastre dos controles Button del Cuadro de herramientas al formulario y después establezca las propiedades Name y Text de los botones de acuerdo con la tabla siguiente.

    Botón

    Nombre

    Texto

    button1

    startBtn

    Iniciar

    button2

    cancelBtn

    Cancelar

  2. Abra el Cuadro de herramientas, haga clic en la ficha Componentes y, a continuación, arrastre el componente BackgroundWorker al formulario.

    Aparecerá el componente backgroundWorker1 en la Bandeja de componentes.

  3. En la ventana Propiedades, haga clic en el botón Eventos y, a continuación, haga doble clic en los eventos DoWork y RunWorkerCompleted para crear los controladores de eventos.

  4. Inserte el código que lleva mucho tiempo en el controlador de eventos DoWork.

  5. Extraiga los parámetros necesarios para la operación de la propiedad Argument del parámetro DoWorkEventArgs.

  6. Asigne el resultado del cálculo a la propiedad Result de DoWorkEventArgs.

    Éste estará disponible al controlador de eventos RunWorkerCompleted.

    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   
    
    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;
        }
    }
    
  7. Inserte el 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 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   
    
    // 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);
        }
    }
    
  8. 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 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
    
    // 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;
    }
    
  9. En el Diseñador de Windows Forms, haga doble clic en startButton para crear el controlador de eventos Click.

  10. Llame al método RunWorkerAsync en el controlador de eventos Click para startButton.

    Private Sub startButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles startBtn.Click
        Me.backgroundWorker1.RunWorkerAsync(2000)
    End Sub
    
    private void startBtn_Click(object sender, EventArgs e)
    {
        this.backgroundWorker1.RunWorkerAsync(2000);
    }
    
  11. En el Diseñador de Windows Forms, haga doble clic en cancelButton para crear el controlador de eventos Click.

  12. Llame al método CancelAsync en el controlador de eventos Click para cancelButton.

    Private Sub cancelButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles cancelBtn.Click
        Me.backgroundWorker1.CancelAsync()
    End Sub
    
    private void cancelBtn_Click(object sender, EventArgs e)
    {
        this.backgroundWorker1.CancelAsync();
    }
    
  13. En la parte superior del archivo, importe los espacios de nombres System.ComponentModel y System.Threading.

    Imports System
    Imports System.ComponentModel
    Imports System.Drawing
    Imports System.Threading
    Imports System.Windows.Forms
    
    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Threading;
    using System.Windows.Forms;
    
  14. Presione F6 para generar 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 bajo el depurador, éste detectará y mostrará la excepción generada en el método TimeConsumingOperation. Cuando ejecuta la aplicación fuera del depurador, BackgroundWorker controla la excepción y la almacena en memoria caché en la propiedad Error de RunWorkerCompletedEventArgs.

  1. Haga clic en el botón Iniciar para ejecutar una operación asincrónica y, a continuación, 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 MessageBox.

Pasos siguientes

Vea también

Tareas

Cómo: Implementar un formulario que utiliza una operación en segundo plano

Cómo: Ejecutar una operación en segundo plano

Referencia

BackgroundWorker

DoWorkEventArgs

Otros recursos

BackgroundWorker (Componente)