Partilhar via


Mantenha o thread da interface do usuário responsivo

Os usuários esperam que um aplicativo permaneça responsivo enquanto faz computação, independentemente do tipo de máquina. Isso significa coisas diferentes para aplicativos diferentes. Para alguns, isso se traduz em fornecer física mais realista, carregar dados do disco ou da web mais rapidamente, apresentar rapidamente cenas complexas e navegar entre páginas, encontrar direções em um piscar de olhos ou processar dados rapidamente. Independentemente do tipo de computação, os usuários querem que seu aplicativo aja de acordo com sua entrada e elimine instâncias em que ele parece não responder enquanto "pensa".

Seu aplicativo é controlado por eventos, o que significa que seu código executa trabalho em resposta a um evento e, em seguida, fica ocioso até o próximo. O código da plataforma para a interface do usuário (layout, entrada, criação de eventos, etc.) e o código do seu aplicativo para a interface do usuário são executados no mesmo thread da interface do usuário. Apenas uma instrução pode ser executada nesse thread de cada vez, portanto, se o código do aplicativo demorar muito para processar um evento, a estrutura não poderá executar, layout ou gerar novos eventos que representem a interação do usuário. A capacidade de resposta do seu aplicativo está relacionada à disponibilidade do thread da interface do usuário para processar o trabalho.

Você precisa usar o thread da interface do usuário para fazer quase todas as alterações no thread da interface do usuário, incluindo a criação de tipos de interface do usuário e o acesso a seus membros. Você não pode atualizar a interface do usuário a partir de um thread em segundo plano, mas pode postar uma mensagem nela com CoreDispatcher.RunAsync fazer com que o código seja executado lá.

Observação A única exceção é que há um thread de renderização separado que pode aplicar alterações na interface do usuário que não afetarão como a entrada é manipulada ou o layout básico. Por exemplo, muitas animações e transições que não afetam o layout podem ser executadas neste thread de renderização.

Atraso na instanciação do elemento

Alguns dos estágios mais lentos em um aplicativo podem incluir inicialização e alternância de modos de exibição. Não faça mais trabalho do que o necessário para exibir a interface do usuário que o usuário vê inicialmente. Por exemplo, não crie a interface do utilizador com revelação progressiva e o conteúdo dos pop-ups.

CoreDispatcher.RunIdleAsync coloca na fila para que o thread da UI processe o trabalho quando não estiver ocupado.

Usar APIs assíncronas

Para ajudar a manter seu aplicativo responsivo, a plataforma fornece versões assíncronas de muitas de suas APIs. Uma API assíncrona garante que seu thread de execução ativo nunca seja bloqueado por um período significativo de tempo. Quando você chamar uma API a partir do thread da interface do usuário, use a versão assíncrona, se estiver disponível. Para saber mais sobre programação com padrões assíncronos , veja de programação assíncrona ou APIs assíncronas de chamada em C# ou Visual Basic.

Transferir o trabalho para threads em segundo plano

Escreva manipuladores de eventos para retornar rapidamente. Nos casos em que uma quantidade não trivial de trabalho precisa ser executada, agende-a em um thread em segundo plano e retorne.

Você pode agendar o trabalho de forma assíncrona usando o operador await em C#, o operador Await no Visual Basic ou delegados em C++. Mas isso não garante que o trabalho agendado será executado em um thread em segundo plano. Muitas das APIs da Plataforma Universal do Windows (UWP) agendam trabalho automaticamente no thread de fundo, mas se invocar o código do aplicativo usando apenas await ou um delegado, executará esse delegado ou método no thread de interface do utilizador. Você precisa dizer explicitamente quando deseja executar o código do aplicativo em um thread em segundo plano. Em C# e Visual Basic você pode fazer isso passando código para Task.Run.

Lembre-se de que os elementos da interface do usuário só podem ser acessados a partir do thread da interface do usuário. Use o thread da interface do usuário para acessar os elementos da interface do usuário antes de iniciar o trabalho em segundo plano e/ou use CoreDispatcher.RunAsync ou CoreDispatcher.RunIdleAsync no thread em segundo plano.

Um exemplo de trabalho que pode ser realizado em um thread de segundo plano é o cálculo da IA do computador em um jogo. O código que calcula o próximo movimento do computador pode levar muito tempo para ser executado.

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

Neste exemplo, o manipulador de NextMove_Click retorna no aguarda para manter a thread de interface do utilizador responsiva. Mas a execução é retomada nesse manipulador novamente depois que ComputeNextMove (que é executado em um thread em segundo plano) é concluída. O código restante no manipulador atualiza a interface do usuário com os resultados.

Observação Há também uma ThreadPool e API de ThreadPoolTimer para a UWP, que pode ser usada para cenários semelhantes. Para obter mais informações, consulte Threading e programação assíncrona.