De UI-thread responsief houden

Gebruikers verwachten dat uw app responsief blijft tijdens het uitvoeren van berekeningen, ongeacht het type computer. Dit betekent verschillende dingen voor verschillende apps: realistische fysica, het laden van gegevens van schijf of het web, het presenteren van complexe scènes, navigeren tussen pagina's of het verwerken van gegevens. Ongeacht het type berekening willen gebruikers dat uw app reageert op hun invoer en voorkomen dat deze niet reageert.

Uw app is gebeurtenisgestuurd: uw code voert werk uit als reactie op een gebeurtenis en zit vervolgens inactief tot de volgende gebeurtenis. Platformcode voor de gebruikersinterface (indeling, invoer, het genereren van gebeurtenissen) en de code van uw app voor de gebruikersinterface worden allemaal uitgevoerd op dezelfde UI-thread. Er wordt slechts één instructie tegelijk uitgevoerd op die thread, dus als uw app-code te lang duurt om een gebeurtenis te verwerken, kan het framework de indeling niet uitvoeren of nieuwe gebeurtenissen genereren. De reactiesnelheid van uw app is gerelateerd aan de beschikbaarheid van de UI-thread voor het verwerken van werk.

U moet de UI-thread gebruiken om bijna alle wijzigingen aan te brengen in ui-elementen. U kunt de gebruikersinterface niet bijwerken vanuit een achtergrondthread, maar u kunt er een bericht naar posten met DispatcherQueue.TryEnqueue om ervoor te zorgen dat de code daar wordt uitgevoerd.

Important

Gebruik in WinUI 3 desktop-apps DispatcherQueue in plaats van de UWP CoreDispatcher. Benader de dispatcher-wachtrij via de eigenschap DispatcherQueue van uw venster of via DispatcherQueue.GetForCurrentThread().

Note

Een afzonderlijke weergavethread kan ui-wijzigingen toepassen die niet van invloed zijn op de manier waarop invoer wordt verwerkt of de basisindeling. Veel animaties en overgangen die geen invloed hebben op de indeling, kunnen bijvoorbeeld worden uitgevoerd op deze renderthread.

Instantiëring van het element vertragen

Enkele van de traagste fasen in een app zijn opstarten en schakelen tussen weergaven. Doe niet meer werk dan nodig is om de gebruikersinterface weer te geven die de gebruiker in eerste instantie ziet. Maak bijvoorbeeld niet de gebruikersinterface voor progressief openbaar gemaakte inhoud of pop-upinhoud.

  • Gebruik het kenmerk x:Load om elementen met vertraging te instantiëren.
  • Voeg naar behoefte programmatisch elementen in de boomstructuur in.

Gebruik DispatcherQueue.TryEnqueue met een lage prioriteit om werk in de wachtrij te plaatsen zodat de UI-thread het kan verwerken wanneer die niet bezig is.

Asynchrone API's gebruiken

Gebruik asynchrone versies van API's wanneer deze beschikbaar zijn om uw app responsief te houden. Een asynchrone API zorgt ervoor dat uw actieve uitvoeringsthread nooit gedurende een aanzienlijke tijd blokkeert. Wanneer u een API aanroept vanuit de UI-thread, gebruikt u altijd de asynchrone versie als deze bestaat.

Verplaats werk naar achtergrondthreads

Schrijf eventhandlers zodat ze snel terugkeren. Wanneer er een niet-triviale hoeveelheid werk moet worden uitgevoerd, plant u dit op een achtergrondthread in en keert u terug.

U kunt werk asynchroon plannen met behulp van de await operator in C#. Echter garandeert await niet dat het werk op een achtergrondthread wordt uitgevoerd. Veel Windows App SDK API's plannen werk op een achtergrondthread voor u, maar als u uw app-code alleen awaitaanroept, voert u die methode uit op de UI-thread. U moet uw app-code expliciet uitvoeren op een achtergrondthread. In C# kunt u dit doen door code door te geven aan Task.Run.

Houd er rekening mee dat u alleen toegang hebt tot UI-elementen vanuit de UI-thread. Gebruik de UI-thread voor toegang tot UI-elementen voordat u achtergrondwerk start of gebruik DispatcherQueue.TryEnqueue op de achtergrondthread om UI-updates terug te plaatsen naar de UI-thread.

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.
    }
}

In dit voorbeeld keert de NextMove_Click-handler bij de await terug om de UI-thread responsief te houden. De uitvoering wordt in die handler weer hervat nadat ComputeNextMove (dat op een achtergrondthread wordt uitgevoerd) is afgerond, en de resterende code werkt de UI bij met de resultaten.