Aufrechterhalten der Reaktionsfähigkeit des UI-Threads

Benutzer erwarten, dass Ihre App reaktionsfähig bleibt, während sie die Berechnung durchführt, unabhängig vom Computertyp. Dies bedeutet unterschiedliche Dinge für verschiedene Apps – die Bereitstellung realistischer Physik, Laden von Daten vom Datenträger oder web, Darstellen komplexer Szenen, Navigieren zwischen Seiten oder Verarbeiten von Daten. Unabhängig vom Typ der Berechnung möchten Benutzer, dass Ihre App auf ihre Eingabe reagiert und Instanzen beseitigt, in denen sie nicht reagiert.

Ihre App ist ereignisgesteuert: Ihr Code führt als Reaktion auf ein Ereignis Arbeit aus und sitzt dann im Leerlauf bis zum nächsten Ereignis. Plattformcode für ui (Layout, Eingabe, Auslösen von Ereignissen) und der Code Ihrer App für die Ui werden alle im selben UI-Thread ausgeführt. Nur eine Anweisung wird jeweils für diesen Thread ausgeführt. Wenn der App-Code also zu lange dauert, um ein Ereignis zu verarbeiten, kann das Framework kein Layout ausführen oder neue Ereignisse auslösen. Die Reaktionsfähigkeit Ihrer App hängt mit der Verfügbarkeit des UI-Threads zusammen, um die Arbeit zu verarbeiten.

Sie müssen den UI-Thread verwenden, um fast alle Änderungen an UI-Elementen vorzunehmen. Sie können die Benutzeroberfläche nicht aus einem Hintergrundthread aktualisieren, aber Sie können eine Nachricht mit DispatcherQueue.TryEnqueue veröffentlichen, um Code dort auszuführen.

Important

Verwenden Sie DispatcherQueue in WinUI 3-Desktop-Apps anstelle der UWP CoreDispatcher. Greifen Sie über die Eigenschaft DispatcherQueue Ihres Fensters oder über DispatcherQueue.GetForCurrentThread() auf die Dispatcherwarteschlange zu.

Note

Ein separater Renderthread kann UI-Änderungen anwenden, die sich nicht auf die Behandlung von Eingaben oder das grundlegende Layout auswirken. Viele Animationen und Übergänge, die sich nicht auf das Layout auswirken, können beispielsweise in diesem Renderthread ausgeführt werden.

Instanziierung des Verzögerungselements

Einige der langsamsten Phasen einer App umfassen Start- und Wechselansichten. Führen Sie nicht mehr Arbeit aus, als erforderlich, um die Benutzeroberfläche anzuzeigen, die der Benutzer anfänglich sieht. Erstellen Sie beispielsweise die Benutzeroberfläche nicht für schrittweise offengelegte Inhalte oder Popupinhalte.

  • Verwenden Sie das x:Load-Attribut, um Elemente verzögert zu instanziieren.
  • Fügen Sie Elemente programmgesteuert bei Bedarf in die Struktur ein.

Verwenden Sie DispatcherQueue.TryEnqueue mit niedriger Priorität, um Arbeit in die Warteschlange für den UI-Thread einzureihen, damit dieser sie verarbeitet, wenn er nicht ausgelastet ist.

Verwenden von asynchronen APIs

Verwenden Sie asynchrone VERSIONEN von APIs, wenn sie verfügbar sind, um ihre App reaktionsfähig zu halten. Eine asynchrone API stellt sicher, dass Ihr aktiver Ausführungsthread niemals für einen erheblichen Zeitraum blockiert wird. Wenn Sie eine API aus dem UI-Thread aufrufen, verwenden Sie immer die asynchrone Version, falls vorhanden.

Arbeit in Hintergrundthreads auslagern

Schreiben Sie Ereignishandler so, dass sie schnell zurückkehren. Wenn ein nicht unerheblicher Arbeitsaufwand erforderlich ist, führen Sie ihn in einem Hintergrundthread aus und kehren Sie zurück.

Sie können die Arbeit asynchron planen, indem Sie den await Operator in C# verwenden. await garantiert jedoch nicht, dass die Arbeit in einem Hintergrundthread ausgeführt wird. Viele Windows App SDK-APIs führen Aufgaben für Sie in einem Hintergrundthread aus, aber wenn Sie den Code Ihrer App ausschließlich mit await aufrufen, führen Sie diese Methode auf dem UI-Thread aus. Sie müssen Den App-Code explizit in einem Hintergrundthread ausführen. Dies erreichen Sie in C#, indem Sie Code an Task.Run übergeben.

Denken Sie daran, dass Sie nur über den UI-Thread auf UI-Elemente zugreifen können. Verwenden Sie den UI-Thread, um vor dem Starten der Hintergrundarbeit auf UI-Elemente zuzugreifen, oder verwenden DispatcherQueue.TryEnqueue Sie den Hintergrundthread, um UI-Aktualisierungen wieder im UI-Thread zu veröffentlichen.

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 diesem Beispiel kehrt der NextMove_Click-Handler bei await zurück, damit der UI-Thread reaktionsfähig bleibt. Die Ausführung wird in diesem Handler nach Abschluss von ComputeNextMove wieder fortgesetzt (das in einem Hintergrundthread ausgeführt wird), und der verbleibende Code aktualisiert die Benutzeroberfläche mit den Ergebnissen.