Uso de async/await en C#, parte 2: Reportar Progreso

En el post anterior vimos como ejecutar tareas en un hilo separado al de la GUI. Si bien esto evita que se bloquee la interfaz, el problema es que el usuario no sabe si la operación esta corriendo, se bloqueo, se finalizo… etc.

Esta guia también esta disponible en forma de video, si asi lo preferís:

Entonces, uando una operación se hace muy larga, se vuelve necesario notificar al usuario del estado. Para esto tenemos la interfaz IProgress que, por supuesto, también es genérica.

Un ejemplo de uso es el siguiente:

private async void button1_Click(object sender, EventArgs e)
{
    var progress = new Progress<int>(pct => progressBar1.Value = pct);

    label1.Text = "Operacion Larga";
    try
    {
        var x=await LongOperationAsync(progress);
        label1.Text = x.ToString();
    }
    catch (Exception ex)
    {
        label1.Text = ex.Message;
    }
}

async Task<int> LongOperationAsync(IProgress<int> progresser)
{
    return await Task.Run<int>(() => { return LongOperation(progresser); });
}

int LongOperation(IProgress<int> progresser)
{
    for (int i = 0; i <= 100; i += 10)
    {
        System.Threading.Thread.Sleep(30);
        if (progresser != null)
            progresser.Report(i);
    }
    //throw new Exception("Ex");
    return 25;
}

Vemos que hicimos varios cambios:

  • En la linea 3, creamos una instancia de la clase Progress, que implementa IProgress. Es importante notar que el lambda definido dentro de esta clase se ejecutará en el hilo de la UI. Es decir, al llamar a Report, se invocará desde el hilo asíncrono al hilo principal. Como vemos, desde aquí seteamos el valor de una ProgressBar.
  • En la linea 17 cambiamos el método para que reciba un parametro IProgress, y en la linea 19 pasamos ese parámetro al llamar al Task.
  • en las lineas 27 y 28 notificamos el progreso. Si el IProgress es nulo, no se notifica nada.

Dos cosas quedan claras aquí:

  1. Somos los responsables de notificar el progreso. Si la operación es muy larga deberemos ver como partirla para poder ir notificando el progreso.
  2. El valor no necesariamente es un int. Puede ser cualquier cosa: un String con el mensaje de error, una enumeración con estados predeterminados, etc.

En el siguiente post veremos como cancelar las operaciones largas.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *