Utilizamos cookies propias y de terceros. [Más información sobre las cookies].
Política de cookies
Proyecto AjpdSoft

· Inicio
· Buscar
· Contactar
· Cookies
· Descargas
· Foros
· Historia
· Nosotros
· Temas
· Top 10
· Trucos
· Tutoriales
· Wiki

Programación: Crear proceso en segundo plano con barra de progreso en Visual Basic .Net VB.Net
Visual Studio .NET


Explicamos con un ejemplo cómo implementar la ejecución de un proceso o tarea en segundo plano con el lenguaje de programación Microsoft Visual Basic .Net 2010. Mostramos el código fuente source code de una aplicación de ejemplo que ejecuta un proceso en segundo plano con barra de progreso usando el componente BackgroundWorker.



Hilo de ejecución, Threads

Un hilo de ejecución o subproceso es una característica que permite a una aplicación realizar varias tareas a la vez (concurrentemente). Los distintos hilos de ejecución comparten una serie de recursos tales como el espacio de memoria, los archivos abiertos, situación de autenticación, etc. Esta técnica permite simplificar el diseño de una aplicación que debe llevar a cabo distintas funciones simultáneamente.

Un hilo es básicamente una tarea que puede ser ejecutada en paralelo con otra tarea.

Los hilos de ejecución que comparten los mismos recursos, sumados a estos recursos, son en conjunto conocidos como un proceso. El hecho de que los hilos de ejecución de un mismo proceso compartan los recursos hace que cualquiera de estos hilos pueda modificar éstos. Cuando un hilo modifica un dato en la memoria, los otros hilos acceden a ese dato modificado inmediatamente.

Lo que es propio de cada hilo es el contador de programa, la pila de ejecución y el estado de la CPU (incluyendo el valor de los registros).

El proceso sigue en ejecución mientras al menos uno de sus hilos de ejecución siga activo. Cuando el proceso finaliza, todos sus hilos de ejecución también han terminado. Asimismo en el momento en el que todos los hilos de ejecución finalizan, el proceso no existe más y todos sus recursos son liberados.

 

Componente BackgroundWorker en Visual Basic .Net VB.Net

El componente BackgroundWorker permite que el formulario o control ejecute operaciones de forma asincrónica. Proporciona la posibilidad de ejecutar operaciones que llevan mucho tiempo de forma asincrónica ("en segundo plano"), en un subproceso distinto del subproceso de la IU principal de la aplicación.

La clase BackgroundWorker permite ejecutar una operación en un subproceso dedicado e independiente. Durante la ejecución de operaciones que exigen mucho tiempo, como las descargas y las transacciones de las bases de datos, puede parecer que la interfaz de usuario (UI) ha dejado de responder. Cuando se necesita una interfaz de usuario rápida, pero se producen largos retrasos asociados a tales operaciones, la clase BackgroundWorker ofrece una práctica solución.

Para ejecutar en segundo plano una operación que exija mucho tiempo, cree un objeto BackgroundWorker y realice escuchas de eventos que creen informes del progreso de la operación y que señalen su finalización. Se puede crear BackgroundWorker mediante programación o arrastrarlo al formulario desde la ficha Componentes del Cuadro de herramientas. Si crea BackgroundWorker en el Diseñador de Windows Forms, aparecerá en la Bandeja de componentes y sus propiedades se mostrarán en la ventana Propiedades.

 

Diseño del formulario Microsoft Visual Basic .Net VB.Net

Para el formulario de ejemplo de uso del componente BackgroundWorker (en el formulario llamado "hiloSegundoPlano") añadiremos los siguientes componentes:

  • NumericUpDown: para establecer el número de iteraciones de la función de Fibonacci que será la usada en el ejemplo para realizar un cálculo que tarde un tiempo determinado y así probar el proceso en segundo plano.
  • Label: mostrará el estado de la tarea ejecutada en segundo plano o background.
  • ProgressBar: barra de progreso que mostrará el porcejate completado de la tarea en segundo plano.
  • Button: botón para iniciar el proceso en segundo plano.
  • Button: botón para cancelar el proceso en segundo plano ejecutado.
  • TextBox: donde el usuario podrá escribir para comprobar que el proceso en segundo plano se está ejecutando y se puede, a su vez, interactuar con el formulario.
  • Button: para limpiar el contenido del TextBox anterior.
  • Button: para guardar el contenido del TextBox anterior, incluso aunque se esté ejecutando el proceso en segundo plano.
  • BackgroundWorker: componente para generar el hilo o proceso en segundo plano, asíncrono o background.
  • SaveFileDialog: componente para mostrar una ventana de petición de unidad, carpeta y nombre del fichero a guardar.

Diseño del formulario Microsoft Visual Basic .Net VB.Net

Estableceremos a True las propiedades WorkerReportsProgress y WorkerSupportsCancellation del componente BackgroundWorker:

Diseño del formulario Microsoft Visual Basic .Net VB.Net

 

 

Desarrollar aplicación con subproceso en segundo plano o asíncrono con Visual Basic .Net

En primer lugar crearemos un proyecto basado en Windows, desde el menú "Archivo" - "Nuevo proyecto", seleccionando "Aplicación de Windows Forms". Añadiremos los componentes que indicamos aquí al formluario principal de la aplicación.

Crearemos el procedimiento o función que será la que realice la acción que queramos ejecutar en proceso en segundo plano. Es importante mencionar que en dicho procedimiento o función no se puede hacer referencia a controles del formulario. Por ejemplo, si queremos mostrar una barra de progreso con el estado de la tarea, deberemos hacer referencia a la barra de progreso en el evento ProgressChanged del componente BackgroundWorker, si intentamos hacer una referencia a algún componente del formulario desde el procedimiento o función se producirá un error.

Añadiremos dicho procedimiento, en nuestro caso un ejemplo de cálculo de la Sucesión de Fibonacci:

    Function CalcularFibonacci(ByVal n As Integer,
                   ByVal worker As BackgroundWorker,
                   ByVal e As DoWorkEventArgs) As Long

        'No permitimos valores superiores a 91 ni inferiores a 9
        If n < 0 OrElse n > 91 Then
            Throw New ArgumentException( _
                "value must be >= 0 and <= 91", "n")
        End If

        Dim result As Long = 0

        iteraciones = iteraciones + 1

        'Si el usuario ha pulsado el botón cancelar abortar la operación
        If worker.CancellationPending Then
            e.Cancel = True
        Else
            If n < 2 Then
                result = 1
            Else
                result = CalcularFibonacci(n - 1, worker, e) + _
                         CalcularFibonacci(n - 2, worker, e)
            End If

            'Establecemos el % de progreso realizado del total de la tarea
            Dim percentComplete As Integer = _
                CSng(n) / CSng(numberToCompute) * 100
            If percentComplete > highestPercentageReached Then
                highestPercentageReached = percentComplete
                worker.ReportProgress(percentComplete)
            End If
        End If

        Return result
    End Function

En la función anterior hemos incluido las líneas de código:

 If worker.CancellationPending Then
   e.Cancel = True
 Else
	....

Para controlar si el usuario ha pulsado el botón cancelar, de esta forma cancelaremos el proceso en segundo plano.

También la línea:

worker.ReportProgress(percentComplete)

 

Para devolver el porcentaje actual del progreso.

Como se puede observar en el código de la función, nunca se hace referencia a un componente del formulario.

Por otro lado en el evento DoWork del componente BackgroundWorker, agregaremos una llamada al método CalcularFibonacci:

    Private Sub hiloSegundoPlano_DoWork(ByVal sender As System.Object,
              ByVal e As System.ComponentModel.DoWorkEventArgs) _
              Handles hiloSegundoPlano.DoWork
        'Obtener el objeto BackgroundWorker que provocó este evento
        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)

        'Asignar el resultado de la computación a la propiedad Result 
        'del objeto DoWorkEventArgs
        e.Result = CalcularFibonacci(e.Argument, worker, e)
    End Sub

En el procedimiento anterior (DoWork) ejecutaremos la función CalcularFibonacci pasándole varios parámetros para permtir la cancelación del proceso y para mostrar la información del progreso.

Es importante que el controlador de eventos DoWork no haga referencia directamente a la variable de la instancia BackgroundWorker (en el ejemplo llamado "hiloSegundoPlano"), ya que esto uniría este controlador de eventos a una instancia específica de BackgroundWorker. En su lugar, se recupera del parámetro sender una referencia al control BackgroundWorker que provocó este evento. Esto es importante cuando el formulario aloje más de un BackgroundWorker.

Para implementar la información de progreso, declaremos tres variables en el formulario formProceso. Éstas se utilizarán para realizar el seguimiento del progreso:

 Public Class formProceso
    Private numeroSeriesFib As Integer = 0
    Private highestPercentageReached As Integer = 0
    Private iteraciones As Integer

En el evento ProgressChanged del componente BackgroundWorker añadiremos el siguiente código:

Private Sub hiloSegundoPlano_ProgressChanged(ByVal sender As Object,
                ByVal e As System.ComponentModel.ProgressChangedEventArgs) _
                Handles hiloSegundoPlano.ProgressChanged
        barraProgreso.Value = e.ProgressPercentage
        lInfo.Text = "Iteraciones Fibonacci: " & CStr(iteraciones)
End Sub

 

Para permitir que el usuario pueda cancelar el proceso en segundo plano, en el evento OnClick del botón btCancelarProceso introduciremos el siguiente código:

    Private Sub btCancelarProceso_Click(ByVal sender As System.Object,
                 ByVal e As System.EventArgs) Handles btCancelarProceso.Click
        'Cancelar proceso asíncrono
        hiloSegundoPlano.CancelAsync()

        'Deshabilitar el botón cancelar
        btCancelarProceso.Enabled = False
    End Sub

Con estos procedimientos habremos conseguido ejecutar la función deseada (CalcularFibonacci) que puede realizar cualquier acción en segundo plano, de forma que de cara al usuario la función o procedimiento se ejecutará "sin que se entere" (si así lo deseamos). Podrá seguir interacturando con nuestra aplicación mientras se ejecuta la tarea en segundo plano. Este método es muy útil para determinados procesos donde consideremos que el usuario ni tiene que interactuar, mejorando así el rendimiento de nuestra aplicación.

 

Código fuente source code completo de aplicación con thread o hilo asíncrono con Visual Basic .Net VB.Net

A continuación mostramos el código fuente complento en Microsoft Visual Basic .Net de Microsoft Visual Studio 2010 como ejemplo de ejecución de tareas en segundo plano o asíncronas, con barra de progreso:

Imports System
Imports System.Threading
Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Imports System.Windows.Forms
Imports System.IO


Public Class formProceso
    Private numeroSeriesFib As Integer = 0
    Private iteraciones As Integer
    Private porcentajeMasAlto As Integer = 0


    Function CalcularFibonacci(ByVal n As Integer,
                   ByVal worker As BackgroundWorker,
                   ByVal e As DoWorkEventArgs) As Long

        'No permitimos valores superiores a 91 ni inferiores a 9
        If n < 0 OrElse n > 91 Then
            Throw New ArgumentException( _
                "value must be >= 0 and <= 91", "n")
        End If

        Dim result As Long = 0

        iteraciones = iteraciones + 1

        'Si el usuario ha pulsado el botón cancelar abortar la operación
        If worker.CancellationPending Then
            e.Cancel = True
        Else
            If n < 2 Then
                result = 1
            Else
                result = CalcularFibonacci(n - 1, worker, e) + _
                         CalcularFibonacci(n - 2, worker, e)
            End If

            'Establecemos el % de progreso realizado del total de la tarea
            Dim porcentajeCompletado As Integer
            porcentajeCompletado = CSng(n) / CSng(numeroSeriesFib) * 100
            If porcentajeCompletado > porcentajeMasAlto Then
                porcentajeMasAlto = porcentajeCompletado
                worker.ReportProgress(porcentajeCompletado)
            End If
        End If

        Return result
    End Function




    Private Sub btIniciarProceso_Click(ByVal sender As System.Object,
                   ByVal e As System.EventArgs) Handles btIniciarProceso.Click

        iteraciones = 0
        barraProgreso.Minimum = 0
        barraProgreso.Maximum = 100

        lInfo.Text = [String].Empty

        'Deshabilitamos el ListBox con el número de iteraciones
        'hasta que concluya el proceso
        txtNumeroIteraciones.Enabled = False

        'Deshabilitar el botón de inicio de proceso
        'hasta que el proceso asíncrono haya concluido
        btIniciarProceso.Enabled = False

        'Habilitamos el botón cancelar
        'mientras la operación está ejecutándose
        btCancelarProceso.Enabled = True

        'Obtenemos el valor de iteraciones seleccionado por el usuario
        numeroSeriesFib = CInt(txtNumeroIteraciones.Value)

        'Iniciamos el valor de la variable que contendrá el % del progreso
        porcentajeMasAlto = 0


        'Iniciamos el proceso asíncrono en segundo plano
        hiloSegundoPlano.RunWorkerAsync(numeroSeriesFib)
    End Sub

    Private Sub btLimpiar_Click(ByVal sender As System.Object,
                 ByVal e As System.EventArgs) Handles btLimpiar.Click
        txtTexto.Text = [String].Empty
    End Sub

    Private Sub btGuardar_Click(ByVal sender As System.Object,
                  ByVal e As System.EventArgs) Handles btGuardar.Click
        dlGuardar.Filter = "Archivos de texto (*.txt)|*.txt|Todos (*.*)|*.*"
        dlGuardar.FilterIndex = 1
        dlGuardar.DefaultExt = "txt"
        dlGuardar.FileName = "texto"
        dlGuardar.OverwritePrompt = True
        dlGuardar.Title = "Guardar fichero mientras se ejecuta tarea en segundo plano"
        If dlGuardar.ShowDialog Then
            Try
                Dim fichero As New StreamWriter(dlGuardar.FileName)
                fichero.WriteLine(txtTexto.Text)
                fichero.Close()
            Catch ex As Exception
                MsgBox(ex.Message, MsgBoxStyle.OkOnly + _
                       MsgBoxStyle.Exclamation)
            End Try
        End If
    End Sub

    Private Sub hiloSegundoPlano_DoWork(ByVal sender As System.Object,
              ByVal e As System.ComponentModel.DoWorkEventArgs) _
              Handles hiloSegundoPlano.DoWork
        'Obtener el objeto BackgroundWorker que provocó este evento
        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)

        'Asignar el resultado de la computación a la propiedad Result 
        'del objeto DoWorkEventArgs
        e.Result = CalcularFibonacci(e.Argument, worker, e)
    End Sub

    Private Sub hiloSegundoPlano_ProgressChanged(ByVal sender As Object,
                ByVal e As System.ComponentModel.ProgressChangedEventArgs) _
                Handles hiloSegundoPlano.ProgressChanged
        barraProgreso.Value = e.ProgressPercentage
        lInfo.Text = "Iteraciones Fibonacci: " & CStr(iteraciones)
    End Sub

    Private Sub hiloSegundoPlano_RunWorkerCompleted(ByVal sender As Object,
                 ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
                 Handles hiloSegundoPlano.RunWorkerCompleted
        'Manejar el caso en que se produzca un error o excepción
        If (e.Error IsNot Nothing) Then
            MsgBox(e.Error.Message, MsgBoxStyle.OkOnly + MsgBoxStyle.Critical)
        Else
            If e.Cancelled Then
                'Manejar el caso en que el usuario haya cancelado la operación. 
                lInfo.Text = "Proceso cancelado"
            Else
                'Manejar el caso en que la operación haya finalizado con éxito
                lInfo.Text = e.Result.ToString()
            End If
        End If

        'Habilitamos el ListBox del número de iteraciones
        txtNumeroIteraciones.Enabled = True

        'Habilitamos el botón de iniciar proceso
        btIniciarProceso.Enabled = True

        'Deshabilitamos el botón cancelar
        btCancelarProceso.Enabled = False
    End Sub

    Private Sub btCancelarProceso_Click(
             ByVal sender As System.Object, 
             ByVal e As System.EventArgs) Handles btCancelarProceso.Click
        'Cancelar proceso asíncrono
        hiloSegundoPlano.CancelAsync()

        'Deshabilitar el botón cancelar
        btCancelarProceso.Enabled = False
    End Sub
End Class

La aplicación AjpdSoft Proceso segundo plano con progreso VB.Net en funcionamiento

Tras seleccionar el número de iteraciones y pulsar en "Iniciar proceso asíncrono" se iniciará el proceso, mostrará la barra de progreso y se activará el botón "Cancelar proceso asíncrono". Si queremos probar que el proceso se ejecuta en segundo plano realmente y que podemos interactuar con la aplicación, podremos escribir en el cuadro de texto y guardar los cambios mientras el proceso se está ejecutando:

La aplicación AjpdSoft Proceso segundo plano con progreso VB.Net en funcionamiento

Si eres desarrollador de software y quieres descargar el ejemplo complento en Microsoft Visual Basic .Net 2010 regístrate en nuestra web y accede al enlace:

AjpdSoft Proceso segundo plano con progreso VB.Net

 

Artículos relacionados

  

Créditos

Artículo realizado íntegramente por Alonsojpd miembro fundador del proyecto AjpdSoft.


Anuncios


Enviado el Sábado, 26 marzo a las 02:06:58 por ajpdsoft
Visita nuestro nuevo sitio web con programas y contenidos actualizados: Proyecto A