Compartir a través de


Mantener la capacidad de respuesta del subproceso de la interfaz de usuario

Los usuarios esperan que una aplicación siga respondiendo mientras realiza el cálculo, independientemente del tipo de máquina. Esto significa diferentes cosas para diferentes aplicaciones. Para algunos, esto se traduce en aportar una física más realista, cargar datos desde un disco o la web de manera más rápida, presentar rápidamente escenas complejas y navegar entre páginas, encontrar direcciones rápidamente o procesar datos de manera veloz. Independientemente del tipo de cálculo, los usuarios quieren que su aplicación actúe en su entrada y elimine las instancias en las que parece que no responde mientras "piensa".

La aplicación está controlada por eventos, lo que significa que el código realiza el trabajo en respuesta a un evento y, a continuación, se coloca inactivo hasta el siguiente. El código de la plataforma para la interfaz de usuario (diseño, entrada, generación de eventos, etc.) y el código de la aplicación para la interfaz de usuario se ejecutan en el mismo subproceso de interfaz de usuario. Solo una instrucción se puede ejecutar en ese subproceso a la vez, por lo que si el código de la aplicación tarda demasiado tiempo en procesar un evento, el marco no puede ejecutar el diseño ni generar nuevos eventos que representen la interacción del usuario. La capacidad de respuesta de la aplicación está relacionada con la disponibilidad del hilo de UI para procesar trabajo.

Debe usar el subproceso de interfaz de usuario para realizar casi todos los cambios en el subproceso de la interfaz de usuario, incluida la creación de tipos de interfaz de usuario y el acceso a sus miembros. No puede actualizar la interfaz de usuario desde un subproceso en segundo plano. Sin embargo, puede enviar un mensaje a la interfaz con CoreDispatcher.RunAsync para que el código se ejecute allí.

Nota La única excepción es que hay un subproceso de representación independiente que puede aplicar cambios de interfaz de usuario que no afectarán a cómo se controla la entrada o el diseño básico. Por ejemplo, muchas animaciones y transiciones que no afectan al diseño se pueden ejecutar en este subproceso de representación.

Retraso en la instanciación de elementos

Algunas de las fases más lentas de una aplicación pueden incluir el inicio y el cambio de vistas. No haga más trabajo de lo necesario para abrir la interfaz de usuario que ve inicialmente el usuario. Por ejemplo, no cree la interfaz de usuario para la interfaz de usuario divulgada progresivamente y el contenido de elementos emergentes.

  • Use el atributo x:Load o la estrategia x:DeferLoadStrategy para retrasar la instanciación de los elementos.
  • Inserte elementos mediante programación en el árbol a petición.

CoreDispatcher.RunIdleAsync colas funcionan para que el subproceso de interfaz de usuario se procese cuando no esté ocupado.

Uso de API asincrónicas

Para ayudar a mantener la capacidad de respuesta de la aplicación, la plataforma proporciona versiones asincrónicas de muchas de sus API. Una API asincrónica garantiza que el subproceso de ejecución activo nunca se bloquee durante un período de tiempo significativo. Al llamar a una API desde el subproceso de interfaz de usuario, use la versión asincrónica si está disponible. Para obtener más información sobre la programación con patrones asincrónicos de , consulte Programación asincrónica o Llamar a API asincrónicas en C# o Visual Basic.

Delegar trabajo a hilos en segundo plano

Escriba controladores de eventos para que se devuelvan rápidamente. En los casos en los que una cantidad de trabajo no trivial deba realizarse, prográmelo en un subproceso en segundo plano y vuelva.

Puede programar el trabajo de forma asincrónica mediante el operador Await en C#, el operador Await en Visual Basic o delegados en C++. Pero esto no garantiza que el trabajo que programe se ejecutará en un subproceso en segundo plano. Muchas de las API de la Plataforma Universal de Windows (UWP) planifican tareas en el hilo de fondo para ti, pero si llamas al código de la aplicación usando solo await o un delegado, ejecutas ese delegado o método en el hilo de la interfaz de usuario. Tienes que decir explícitamente cuándo quieres ejecutar el código de la aplicación en un subproceso en segundo plano. En C# y Visual Basic, puede hacerlo pasando código a Task.Run.

Recuerde que solo se puede acceder a los elementos de la interfaz de usuario desde el subproceso de la interfaz de usuario. Usa el subproceso de interfaz de usuario para acceder a los elementos de la interfaz de usuario antes de iniciar el trabajo en segundo plano o usa CoreDispatcher.RunAsync o CoreDispatcher.RunIdleAsync en el subproceso en segundo plano.

Un ejemplo de trabajo que se puede realizar en un subproceso en segundo plano es el cálculo de la inteligencia artificial de la computadora en un juego. El código que calcula el siguiente movimiento del equipo puede tardar mucho tiempo en ejecutarse.

public class AsyncExample
{
    private async void NextMove_Click(object sender, RoutedEventArgs e)
    {
        // The await causes the handler to return immediately.
        await System.Threading.Tasks.Task.Run(() => ComputeNextMove());
        // Now update the UI with the results.
        // ...
    }

    private async System.Threading.Tasks.Task ComputeNextMove()
    {
        // Perform background work here.
        // Don't directly access UI elements from this method.
    }
}
Public Class AsyncExample
    ' ...
    Private Async Sub NextMove_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Await Task.Run(Function() ComputeNextMove())
        ' update the UI with results
    End Sub

    Private Async Function ComputeNextMove() As Task
        ' ...
    End Function
    ' ...
End Class

En este ejemplo, el controlador de NextMove_Click regresa en el await para que el hilo de la interfaz de usuario siga siendo ágil. Pero la ejecución continúa en ese controlador después de que se complete ComputeNextMove (que se ejecuta en un subproceso en segundo plano). El código restante del controlador actualiza la interfaz de usuario con los resultados.

Nota También hay una ThreadPool y ThreadPoolTimer API para UWP, que se pueden usar para escenarios similares. Para obtener más información, consulta Hilos y programación asincrónica.