Este documento muestra como enviar un informe de progresos, y como cancelar la tarea, ademas , la tarea se realiza en otra clase
Es un formulario con dos botones [Prueba] y [Cancelar] y un TextBox donde se muestra el proceso [TextBox1]
el proceso esta en una clase independiente y consiste en la busqueda de los ficheros de un disco
se utiliza una clase propia [Util.Numeros.PorcentajeRealizadoEventArgs] para el evento de porcentaje
Observa el juego de las palabras claves [Async] y [Await] en el botón [Prueba]
Public Class FormDos '------------ ' El informe del progreso Private progress As New Progress(Of Util.Numeros.PorcentajeRealizadoEventArgs) _ (Sub(percentaje) TextBox1.Text = percentaje.ProcentajeRealizado & "%" End Sub) '------------ ' Define el Token de cancelacion. Private sourceCancellationToken As New System.Threading.CancellationTokenSource() Private tokenCancellation As System.Threading.CancellationToken = sourceCancellationToken.Token '------------ ' La función que hace el trabajo esta en la clase [objClasePruebaDos] ' y en esta clase también se almacena el resultado del proceso Private objClasePruebaDos As New PruebaDosClase '------------ Private Async Sub ButtonPrueba_Click(sender As Object, e As EventArgs) Handles ButtonPrueba.Click '---------------------------- ' Apunte Táctico / problema ' quiero que cada vez que llamo a la función se ejecute ' si he llamado al cancelación, la función se detiene, y cuando vuelco a llamarla el [tokenCancellation] ' tiene el valor [esta cancelada], y , evidentemente, la función no vuelve a ejecutarse. ' para resolver este problema he estado haciendo muchas pruebas, y al final, ' he dado con esta solución, que no se si es la mejor, pero que funciona ' ' fuera de la función se definen las variables [Source] y [Token] ' antes de empezar a trabajar, se usa el dispose para el [source] ' a continuación se vuelve a instanciar las dos variables [Source] y [Token] ' y el proceso vuelve a funcionar cada vez que se llama. '----------------------------------------------- sourceCancellationToken.Dispose() sourceCancellationToken = New System.Threading.CancellationTokenSource() tokenCancellation = sourceCancellationToken.Token ' El directorio lo pongo aquí en el código porque es mas sencillo ' también se puede escoger (por ejemplo) de un TextBox del Form Dim directorioInicio As New System.IO.DirectoryInfo("C:\") ' el proceso Task, que devuelve un valor ' en est caso no lo uso para nada Dim r As Integer = Await Task.Run(Function() Return objClasePruebaDos.RecorrerDirRecursiva(directorioInicio, progress, tokenCancellation) End Function) TextBox1.Text = String.Format("Hecho! [{0}], [{1}]", r, objClasePruebaDos.listaFicherosObservable.Count) End Sub '------------ Private Sub ButtonCancelar_Click(sender As Object, e As EventArgs) Handles ButtonCancelar.Click sourceCancellationToken.Cancel() End Sub End Class
otra forma de lanzar la tarea que tambien funciona
Mas información en Programación asincrónica basada en tareas
#Region "Proceso TASK - Botones Funciones con las acciones " '------------ ' El informe del progreso Private ReadOnly progress As New Progress(Of Util.Numeros.PorcentajeRealizadoEventArgs) _ (Sub(percentaje) Me.ProgressBarEjecutado.Value = percentaje.ProcentajeRealizado TextBoxInformes.Text = percentaje.Identificador End Sub) '------------ ' Define el Token de cancelación. Private sourceCancellationToken As New System.Threading.CancellationTokenSource() Private tokenCancellation As System.Threading.CancellationToken = sourceCancellationToken.Token '------------ ' La función que hace el trabajo esta en la clase [objClasePruebaDos] ' y en esta clase también se almacena el resultado del proceso ' es el objeto [CustomData] Private WithEvents ObjClaseBuscadorFicheros As LayerModelo.BusquedaFicherosIgualesTask ''' <summary> ''' Acción a realizar al pulsar el botón [Ejecutar] ''' </summary> Private Sub AccionButtonEjecutar() '---------------------------- ' Apunte Táctico / problema ' quiero que cada vez que llamo a la función se ejecute ' si he llamado al cancelación, la función se detiene, y cuando vuelco a llamarla el [tokenCancellation] ' tiene el valor [esta cancelada], y , evidentemente, la función no vuelve a ejecutarse. ' para resolver este problema he estado haciendo muchas pruebas, y al final, ' he dado con esta solución, que no se si es la mejor, pero que funciona ' ' fuera de la función se definen las variables [Source] y [Token] ' antes de empezar a trabajar, se usa el dispose para el [source] ' a continuación se vuelve a instanciar las dos variables [Source] y [Token] ' y el proceso vuelve a funcionar cada vez que se llama. '----------------------------------------------- 'sourceCancellationToken.Dispose() sourceCancellationToken = New System.Threading.CancellationTokenSource() tokenCancellation = sourceCancellationToken.Token ' el objeto que tiene las funciones para hacer el trabajo Dim directorioInicialBusqueda As String = "E:\" ObjClaseBuscadorFicheros = New LayerModelo.BusquedaFicherosIgualesTask(progress, tokenCancellation, directorioInicialBusqueda) ' Crear una tarea y proporcionar un delegado de usuario mediante una expresión lambda. Dim taskA As Task(Of Integer) = New Task(Of Integer)(Function() Call ObjClaseBuscadorFicheros.ExecuteTask() Return 1 End Function) ' arrancar la ejecución de la tarea. taskA.Start() ' esperar a que termine la tarea taskA.Wait() ' a) obtener el resultado Dim resultado As Integer = taskA.Result ' b) obtener - Ejecutar tareas en función del valor de TaskStatus ' Valor que hay que actualizar en [] Select Case ObjClaseBuscadorFicheros.TaskStatus Case Is = TaskStatus.RanToCompletion ' la tarea termino de ejecutarse correctamente Call ActualizarListViewDataBindig() Case Is = TaskStatus.Faulted ' la tarea termino debido a una excepción no controlada ' ESTE VALOR ES UN ERROR ' el proceso no debe continuar ' registra el error ' Ventana a su situación inicial TextBoxInformes.Text & = ObjClaseBuscadorFicheros.ResultadoProcesoTaskValidationResult.ErrorContent.ToString 'objClasePruebaDos.ToNotepad() Case Is = TaskStatus.Canceled ' El usuario cancelo la operación ' Proceso cancelado por el usuario. ' Ventana a su situación inicial TextBoxInformes.Text & = ObjClaseBuscadorFicheros.ResultadoProcesoTaskValidationResult.ErrorContent.ToString TextBoxInformes.Text & = Environment.NewLine End Select End Sub '------------ ''' <summary> ''' Acción a realizar al pulsar el botón [Cancelar] ''' </summary> Private Sub AccionButtonCancelar() Call sourceCancellationToken.Cancel() End Sub ''' <summary> ''' Acción a realizar al pulsar el botón [Terminar] ''' </summary> Private Sub AccionButtonTerminar() '------------------------------------------------------------ ' Este es el proceso que se realiza al pulsar el botón [Terminar] Me.Close() '------------------------------------------------------------ End Sub #End Region
A continuación se muestra la clase que contiene el código que realizara la tarea (Task) del formulario
''' <summary> ''' Clase que contiene la tarea que tiene que realizar el Task ''' </summary> Public Class PruebaDosClase Public Property ContadorVueltas As Integer Public Property listaFicherosObservable As New System.Collections.ObjectModel.ObservableCollection(Of System.IO.FileInfo) Public ReadOnly Property IncluirBusquedaEnSubdirectorio As Boolean = True Public Sub New() ' No hacer nada (de momento) End Sub ''' <summary> ''' Recorre el directorio (y opcionalmente, según el valor de la propiedad ''' [IncluirBusquedaEnSubdirectorio] los subdirectorios hijos) y ''' guarda los ficheros el la propiedad de la clase [listaFicherosObservable] ''' </summary> ''' <param name=di">El directorio de inicio de la búsqueda</param>" ''' <param name=progress">el objeto [IProgress] para informar al llamador del progreso de la operación</param>" ''' <param name=tokenCancelacion">el token para cancelar el proceso</param>" ''' <returns> ''' Esta función es recursiva, ''' devuelve 0 = falso si hay algún error, y 1 = verdadero si acaba de forma normal ''' </returns> Public Function RecorrerDirRecursiva( ByVal di As System.IO.DirectoryInfo, ByVal progress As IProgress(Of Util.Numeros.PorcentajeRealizadoEventArgs), ByVal tokenCancelacion As System.Threading.CancellationToken) As Integer If progress IsNot Nothing Then ' como no se cuantos ficheros voy a encontrar, cada 5000 ficheros empiezo de nuevo a contar ' de esta forma el progress bar, se llena y luego vuelve a empezar llenarse otra vez ContadorVueltas += 1 If ContadorVueltas >= 5000 Then ContadorVueltas = 1 End If progress.Report(New Util.Numeros.PorcentajeRealizadoEventArgs(ContadorVueltas, 5000, di.FullName)) End If ' Recorrer los ficheros de este directorio Dim fics() As System.IO.FileInfo Dim dirs() As System.IO.DirectoryInfo Try If Not (tokenCancelacion = Nothing) Then If tokenCancelacion.IsCancellationRequested = True Then Exit Try End If End If ' Primero leer los ficheros fics = di.GetFiles("*", System.IO.SearchOption.TopDirectoryOnly) For Each fi As System.IO.FileInfo In fics listaFicherosObservable.Add(fi) Next 'Después leer los directorios If IncluirBusquedaEnSubdirectorio = True Then dirs = di.GetDirectories() For Each dir As System.IO.DirectoryInfo In dirs RecorrerDirRecursiva(dir, progress, tokenCancelacion) Next End If Catch ex As Exception Console.WriteLine(ex.Message) Return 0 End Try Return 1 End Function End Class
© 1997 - - La Güeb de Joaquín | |||||
Joaquín Medina Serrano
|
|||||
|
Codificación | |
Fecha de creación | [2016-09-13T08:41:17] |
Última actualización | |
![]() |