Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Os utilizadores esperam que a sua aplicação se mantenha responsiva enquanto realiza os cálculos, independentemente do tipo de máquina. Isto significa coisas diferentes para aplicações diferentes — fornecer física realista, carregar dados do disco ou da web, apresentar cenas complexas, navegar entre páginas ou processar dados. Independentemente do tipo de cálculo, os utilizadores querem que a sua aplicação aja com base na sua entrada e elimine situações em que pareça não responsiva.
A sua aplicação é orientada por eventos: o seu código realiza trabalho em resposta a um evento e depois fica inativo até ao evento seguinte. O código da plataforma para a interface do utilizador (esquema, entrada, geração de eventos) e o código da tua aplicação para a interface do utilizador são ambos executados na mesma thread da interface do utilizador. Apenas uma instrução é executada nesse thread de cada vez, por isso, se o código da tua aplicação demorar demasiado tempo a processar um evento, o framework não consegue executar layout nem gerar novos eventos. A capacidade de resposta da tua aplicação está relacionada com a disponibilidade da thread da IU para processar tarefas.
Precisas de usar o tópico da interface para fazer quase todas as alterações aos elementos da interface. Não podes atualizar a interface a partir de um tópico em segundo plano, mas podes enviar uma mensagem nela através do DispatcherQueue.TryEnqueue para fazer com que o código seja executado lá.
Importante
Nas aplicações de desktop do WinUI 3, use DispatcherQueue em vez do UWP CoreDispatcher. Aceda à fila do dispatcher através da propriedade DispatcherQueue da sua janela ou de DispatcherQueue.GetForCurrentThread().
Note
Um thread de renderização separado pode aplicar alterações à interface que não afetam a forma como o input é tratado ou o layout básico. Por exemplo, muitas animações e transições que não afetam o layout podem correr neste tópico de renderização.
Instância de elementos de atraso
Algumas das fases mais lentas de uma aplicação incluem arranque e troca de vistas. Não faça mais trabalho do que o necessário para ativar a interface que o utilizador vê inicialmente. Por exemplo, não crie a interface para conteúdos divulgados progressivamente ou pop-ups.
- Utilize o atributo x:Load para instanciar elementos tardiamente.
- Inserir elementos programáticamente na árvore a pedido.
Usa DispatcherQueue.TryEnqueue com baixa prioridade para enfileirar trabalho para o thread da interface processar quando não estiver ocupado.
Usar APIs assíncronas
Para manter a sua aplicação responsiva, use versões assíncronas das APIs quando estiverem disponíveis. Uma API assíncrona garante que o seu fluxo de execução nunca fica bloqueado durante um período de tempo significativo. Quando chamas uma API a partir do thread da interface, usa sempre a versão assíncrona, se existir.
Transferir o processamento para threads de segundo plano
Escreva os gestores de eventos para regressar rapidamente. Quando for necessário realizar uma quantidade não trivial de trabalho, execute esse trabalho numa thread em segundo plano e retorne.
Pode agendar trabalho de forma assíncrona usando o await operador em C#. No entanto, await não garante que o trabalho seja executado numa thread em segundo plano. Muitas APIs do SDK de Aplicações Windows agendam o trabalho num thread em segundo plano para si, mas se chamar o código da sua app usando apenas await, executa esse método no thread da interface. Tens de executar explicitamente o código da tua aplicação num thread em segundo plano. Em C#, faça isto passando código para Task.Run.
Lembra-te que só podes aceder aos elementos da interface a partir do tópico da interface. Utilize a thread da IU para aceder aos elementos da IU antes de iniciar trabalho em segundo plano, ou utilize DispatcherQueue.TryEnqueue na thread em segundo plano para enviar atualizações da IU para a thread da IU.
public sealed partial class MainWindow : Window
{
// Declared in MainWindow.xaml as x:Name="statusText".
private TextBlock statusText;
private async void NextMove_Click(object sender, RoutedEventArgs e)
{
// The await causes the handler to return immediately.
await Task.Run(() => ComputeNextMove());
// Now update the UI with the results.
// This code runs on the UI thread after ComputeNextMove completes.
statusText.Text = "Move computed.";
}
private void ComputeNextMove()
{
// Perform background work here.
// Don't directly access UI elements from this method.
}
}
Neste exemplo, o processador NextMove_Click retorna no await para manter o thread da interface do utilizador responsivo. A execução é retomada nesse handler depois de ComputeNextMove terminar (que é executado numa thread em segundo plano), e o restante código atualiza a interface com os resultados.
Conteúdo relacionado
Windows developer