次の方法で共有


UI スレッドの応答性を維持する

ユーザーは、コンピューターの種類に関係なく、計算を行っている間もアプリの応答性が維持されると想定しています。 これは、アプリごとに異なる意味を持ちます。 一部のユーザーにとっては、より現実的な物理演算の提供、ディスクまたは Web からのデータの読み込み速度の向上、複雑なシーンの迅速な表示、ページ間の移動、スナップでの方向の検索、またはデータの迅速な処理に変換されます。 計算の種類に関係なく、ユーザーはアプリが入力に対して動作し、"考える" 間に応答していないと思われるインスタンスを排除したいと考えています。

アプリはイベント ドリブンです。つまり、コードはイベントに応答して作業を実行し、次のイベントまでアイドル状態になります。 UI のプラットフォーム コード (レイアウト、入力、イベントの発生など) と UI 用のアプリのコードはすべて、同じ UI スレッドで実行されます。 そのスレッドで一度に実行できる命令は 1 つだけであるため、アプリ コードでイベントの処理に時間がかかりすぎる場合、フレームワークはレイアウトを実行したり、ユーザーの操作を表す新しいイベントを発生させたりすることはできません。 アプリの応答性は、UI スレッドを使用して作業を処理できるかどうかに関連します。

UI スレッドを使用して、UI 型の作成やメンバーへのアクセスなど、UI スレッドにほぼすべての変更を加える必要があります。 バックグラウンド スレッドから UI を更新することはできませんが、 CoreDispatcher.RunAsync を使用してメッセージを投稿して、そこでコードを実行させることができます。

手記 1 つの例外は、入力の処理方法や基本的なレイアウトに影響を与えない UI の変更を適用できる別のレンダリング スレッドがあることです。 たとえば、レイアウトに影響しない多くのアニメーションや画面切り替えは、このレンダリング スレッドで実行できます。

要素のインスタンス化を遅らせる

アプリの最も遅いステージには、起動やビューの切り替えなどがあります。 ユーザーが最初に表示する UI を表示するために必要以上の作業を行わないでください。 たとえば、段階的に公開される UI とポップアップの内容の UI は作成しないでください。

  • x:Load 属性 を使用するか、x:DeferLoadStrategy を使用して、要素を遅延してインスタンス化します。
  • プログラムによって要素をツリーにオンデマンドで挿入します。

CoreDispatcher.RunIdleAsync キューは、UI スレッドがビジーでないときに処理するために機能します。

非同期 API の使用

アプリの応答性を維持するために、プラットフォームは多くの API の非同期バージョンを提供します。 非同期 API を使用すると、アクティブな実行スレッドが長時間ブロックされることはありません。 UI スレッドから API を呼び出すときは、使用可能な場合は非同期バージョンを使用します。 非同期 パターン 使用したプログラミングの詳細については、「C# または Visual Basicで非同期プログラミング または 呼び出し非同期 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

この例では、ui スレッドの応答性を維持するために、 NextMove_Click ハンドラーは await で戻ります。 しかし、(バックグラウンド スレッドで実行される) ComputeNextMove が完了した後、実行が再びそのハンドラーで開始されます。 ハンドラーの残りのコードは、結果を使用して UI を更新します。

手記 同様のシナリオで使用できる UWP 用の ThreadPool API と ThreadPoolTimer API もあります。 詳細については、「 スレッド処理と非同期プログラミング」を参照してください。