使用者預期無論計算機類型為何,應用程式都會在計算時保持回應。 對於不同的應用程式,這代表不同的意義。 對於某些人來說,這可以實現更逼真的物理效果、更快速地從磁碟或網路載入資料、快速呈現複雜的場景,順暢地在頁面間瀏覽、快速找到路線或迅速處理資料。 無論計算類型為何,使用者都希望其應用程式在其輸入上採取行動,並排除在「思考」時其看起來沒有回應的實例。
您的應用程式是事件驅動,這表示您的程式代碼會執行工作以回應事件,然後閒置直到下一個事件為止。 UI 的平台程式代碼(配置、輸入、引發事件等)和您的應用程式 UI 程式代碼全都在同一個 UI 線程上執行。 一次只能有一個指令在該線程上執行,因此如果您的應用程式程式代碼處理事件的時間太長,則架構無法執行配置或引發代表用戶互動的新事件。 應用程式的回應性與UI線程的可用性有關,以處理工作。
您必須使用UI線程,對UI線程進行幾乎所有的變更,包括建立UI類型及存取其成員。 您無法從背景執行緒更新 UI,但您可以使用 CoreDispatcher.RunAsync 將訊息傳送至 UI 執行緒,這樣 的程式碼就會在那裡執行。
注意 有一個例外,那就是有一個獨立的呈現執行緒可以進行UI變更,而不會影響如何處理輸入或基本佈局。 例如,許多不會影響版面配置的動畫和轉換都可以在此轉譯線程上執行。
延遲元素實例化
應用程式中一些最慢的階段可能包括啟動和切換檢視。 不要執行比使用者一開始看到UI所需的更多工作。 例如,請勿為漸進式顯示的 UI 和彈出視窗的內容建立 UI。
- 使用 x:Load 屬性 或 x:DeferLoadStrategy 來延遲實體化元素。
- 透過程式在需要時將元素插入樹狀結構。
CoreDispatcher.RunIdleAsync 佇列可讓 UI 線程在空閒時進行處理。
使用非同步 API
為了協助讓應用程式保持回應,平臺會提供許多 API 的異步版本。 異步 API 可確保作用中的執行線程永遠不會長時間封鎖。 當您從 UI 線程呼叫 API 時,如果有可用的異步版本,請使用異步版本。 如需使用
將工作轉移至背景執行緒
撰寫事件處理程式以快速傳回。 在需要大量工作的情況下,請在背景執行緒上排程並返回。
您可以使用 C# 中的 await 運算子、Visual Basic 中的 Await 運算子或 C++ 中的委派,以異步方式排程工作。 但這不保證您排程的工作將在背景線程上執行。 許多通用 Windows 平台 (UWP) API 會為您在背景執行緒中安排工作,但是如果您只使用 await 或委派來呼叫應用程式代碼,您會在 UI 執行緒上執行該委派或方法。 您必須在背景線程上明確說明何時要執行應用程式程序代碼。 在 C# 和 Visual Basic 中,您可以將程式代碼傳遞至 Task.Run 來完成這項作業。
請記住,UI 元素只能從UI線程存取。 在啟動背景工作之前,請使用 UI 執行緒來存取 UI 元素,並且/或在背景執行緒上使用 CoreDispatcher.RunAsync 或 CoreDispatcher.RunIdleAsync。
可以在背景線程上執行的工作範例,就是運算遊戲中的電腦 AI。 計算計算機下一個行動的程式代碼可能需要很多時間才能執行。
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
在此範例中,NextMove_Click
處理程式會傳回 await,以便讓UI線程保持回應。 但在 ComputeNextMove
(在背景執行緒上執行)完成之後,執行會再次在該處理程式中繼續。 處理程式中的其餘程式代碼會使用結果來更新UI。
注意UWP 也有一個 ThreadPool 和 ThreadPoolTimer API,可用於類似的案例。 如需詳細資訊,請參閱 線程和異步程序設計。