讓 UI 執行緒保持回應

使用者期望你的應用程式在執行運算時保持回應,無論機器類型為何。 這對不同應用程式來說意義不同——提供逼真的物理效果、從磁碟或網頁載入資料、呈現複雜場景、頁面間導航,或資料處理。 無論計算方式為何,使用者都希望你的應用程式能根據他們的輸入採取行動,消除它看起來無反應的情況。

你的應用程式是事件驅動的:你的程式碼會根據事件執行工作,然後閒置直到下一個事件發生。 UI 的平台程式碼(佈局、輸入、事件產生)和你應用程式的 UI 程式碼都跑在同一個 UI 執行緒上。 同一執行緒一次只能執行一條指令,所以如果你的應用程式程式碼處理事件太慢,框架就無法執行版面設計或產生新事件。 你的應用程式響應速度與 UI 執行緒處理工作的可用性有關。

你需要使用 UI 執行緒來對 UI 元素進行幾乎所有變更。 你無法從背景執行緒更新 UI,但你可以用 DispatcherQueue.TryEnqueue 發佈訊息,讓程式碼在那裡執行。

Important

在 WinUI 3 桌面應用程式中,請使用 DispatcherQueue UWP CoreDispatcher代替 。 透過您視窗的 DispatcherQueue 屬性或 DispatcherQueue.GetForCurrentThread() 存取分派器佇列。

Note

獨立的渲染執行緒可以套用不影響輸入處理方式或基本版面配置的 UI 變更。 例如,許多不影響版面的動畫和轉場可以在這個渲染執行緒上執行。

延遲元素實例化

應用程式中最慢的階段包括啟動和切換視圖。 不要為了顯示使用者一開始會看到的介面而做超出必要的處理。 例如,不要為漸進式揭露內容或彈出內容建立介面。

  • 使用 x:Load 屬性 來延遲實例化元素。
  • 以程式方式按需將元素插入樹狀結構。

使用 DispatcherQueue.TryEnqueue 以低優先順序將工作排入佇列,供 UI 執行緒在不忙碌時處理。

使用非同步 API

為了讓您的應用程式保持回應靈敏,在 API 提供非同步版本時,請使用該版本。 非同步 API 確保你的主動執行緒在長時間內不會阻塞。 當你從 UI 執行緒呼叫 API 時,如果有非同步版本,務必使用。

將工作交由背景執行緒處理

撰寫事件處理常式時,應使其迅速返回。 當需要執行相當量的工作時,請將其排程到背景執行緒上執行,然後返回。

你可以用 C# 裡的 await 運算子來非同步排程工作。 不過,await 並不保證該工作會在背景執行緒上執行。 許多 Windows 應用程式 SDK API 會幫你將工作排定在背景執行緒上執行,但如果你只是使用 await 來呼叫應用程式程式碼,該方法就會在 UI 執行緒上執行。 你必須明確在背景執行緒上執行你的應用程式程式碼。 在 C# 中,透過將程式碼傳給 Task.Run 來達成此目標。

請記得你只能從 UI 執行緒中存取 UI 元素。 在啟動背景工作前,可以用 UI 執行緒來存取 UI 元素,或在背景執行緒上用 DispatcherQueue.TryEnqueue 來發佈 UI 更新回 UI 執行緒。

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

在這個範例中,NextMove_Click 處理常式會在 await 處返回,以讓 UI 執行緒保持回應能力。 在 ComputeNextMove(於背景執行緒上執行)完成後,執行會回到該處理常式中繼續進行,而其餘程式碼則會使用結果更新使用者介面。