es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cancelando una tarea asíncrona cuando el texto del TextBox cambia y luego reiniciándola

Tengo una aplicación .NET y hay un DataGridView y un TextBox en mi interfaz gráfica de usuario (GUI). Lo que quiero hacer es que cuando el usuario cambie el texto del TextBox, se actualice el DataGridView en las celdas que contengan ese texto. Pero esta búsqueda debe ejecutarse como una tarea asíncrona porque, si no lo hace, provoca congelación en la GUI. Cada vez que el usuario cambie el texto del TextBox, mi aplicación deberá cancelar cualquier otra tarea de búsqueda en ejecución y volver a ejecutarla para buscar de acuerdo a los nuevos valores de búsqueda. Aquí está mi código:

CancellationTokenSource cts = new CancellationTokenSource();
private async void TextBox1_Changed(object sender, EventArgs e)
{
    cts.Cancel();
    CancellationToken ct = cts.Token;
    try
    {
        await Task.Run(() =>
        {
            System.Diagnostics.Debug.WriteLine("Tarea iniciada");

            // Realizar búsqueda aquí.

            System.Diagnostics.Debug.WriteLine("Tarea finalizada");
        }, cts.Token);
    }
    catch
    {
        System.Diagnostics.Debug.WriteLine("Cancelado");
    }
}

En mi código, las tareas se cancelan sin haberse iniciado. Solo veo la línea “Cancelado” en la consola de depuración. Debo cancelar las tareas porque, si no lo hago, el número de tareas y el uso de CPU de la aplicación aumentan. ¿Hay alguna forma de hacerlo?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Para cancelar las tareas correctamente, debes asegurarte de que se observe el token de cancelación en el cuerpo de la tarea. Aquí tienes una versión actualizada de tu código que debería funcionar correctamente:

    private CancellationTokenSource cts = new CancellationTokenSource();
    
    private async void TextBox1_Changed(object sender, EventArgs e)
    {
        cts.Cancel();
        cts = new CancellationTokenSource();
        CancellationToken ct = cts.Token;
        try
        {
            await Task.Run(async () =>
            {
                System.Diagnostics.Debug.WriteLine("Tarea iniciada");
    
                // simulate a long-running search
                await Task.Delay(5000, ct);
    
                System.Diagnostics.Debug.WriteLine("Tarea finalizada");
            }, cts.Token);
        }
        catch (OperationCanceledException)
        {
            System.Diagnostics.Debug.WriteLine("Cancelado");
        }
    }
    

    Aquí están los cambios realizados en el código:

    • Creamos un nuevo CancellationTokenSource cada vez que se cambia el cuadro de texto. Esto asegura que cualquier tarea de búsqueda previa se cancele y se inicie una nueva.
    • Envolvemos el cuerpo de la tarea en una lambda async para poder usar await y observar el token de cancelación. Esto hace que la cancelación sea más receptiva.
    • Capturamos OperationCanceledException en lugar de Exception para manejar correctamente la cancelación. Cuando la tarea se cancela, se lanza esta excepción y podemos manejarla correctamente.
    • Pasamos cts.Token al método Task.Run para que el token de cancelación sea observado por la tarea. Si el token se cancela, se detendrá inmediatamente la tarea y se lanzará OperationCanceledException.

Comments are closed.