12

Dispatcher.RunAsync作業が完了したときではなく、作業がスケジュールされたときに継続待ちが発生する場合。作業の完了をどのように待つことができますか?

編集

私の最初の質問は、時期尚早の継続がAPIの設計によって引き起こされたと想定していたので、ここに本当の質問があります.

デリゲートのコード内でDispatcher.RunAsync非同期デリゲートを使用して待機している場合、作業が完了したときではなく、 が検出されたときに継続が発生します。作業の完了をどのように待つことができますか?awaitawait

編集 2

既に UI スレッドにある作業をディスパッチする必要がある理由の 1 つは、微妙なタイミングとレイアウトの問題を回避することです。ビジュアル ツリー内の要素のサイズと位置の値が流動的であることはよくあることであり、UI の後のイテレーションのために作業をスケジューリングすることが役立ちます。

4

4 に答える 4

5

RunAsync待機できる独自の非同期メソッドで呼び出しをラップし、タスクの完了を制御して、呼び出し元の待機を継続することができます。

async-await は型に集中しているためTask、この型を使用して作業を調整する必要があります。ただし、通常はTaskスレッドプール スレッドで実行するようにスケジュールされるため、UI 作業のスケジュールには使用できません。

ただし、このTaskCompletionSourceタイプは、予定外のTask. 言い換えると、 aは何もスケジュールされていないTaskCompletionSourceダミーを作成できますが、 can のメソッドを介して、通常のジョブのように実行および完了しているように見えます。TaskTaskCompletionSource

この例を参照してください。

public Task PlayDemoAsync()
{
    var completionSource = new TaskCompletionSource<bool>();
    this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
    {
        try
        {
            foreach (var ppc in this.Plots.Select(p => this.TransformPlot(p, this.RenderSize)))
            {
                // For each subsequent stroke plot, we need to start a new figure.
                //
                if (this.Sketch.DrawingPoints.Any())
                    this.Sketch.StartNewFigure(ppc.First().Position);

                foreach (var point in ppc)
                {
                    await Task.Delay(100);

                    this.Sketch.DrawingPoints.Add(point.Position);
                }
            }

            completionSource.SetResult(true);
        }
        catch (Exception e)
        {
            completionSource.SetException(e);
        }
    });

    return (Task)completionSource.Task;
}

注: UI スレッドで行われている主な作業は、100 ミリ秒ごとに画面に描画される線だけです。

ATaskCompletionSourceがパペット マスターとして作成されます。Task最後の方を見ると、呼び出し元に返されるプロパティがあることがわかります。戻るTaskことでコンパイラのニーズが満たされ、メソッドが待機可能になり、非同期になります。

ただし、これTaskは単なる操り人形であり、UI スレッドで行われている実際の作業のプロキシです。

そのメイン UI デリゲートでメソッドを使用して(呼び出し元に返されたので)TaskCompletionSource.SetResult結果を に強制し、作業が完了したことを伝える方法を確認してください。Task

エラーが発生した場合は、SetException「別の文字列をプル」して、パペットで例外が発生したように見せますTask

async-await サブシステムは違いを認識していないため、期待どおりに機能します。

編集

svick が促したように、メソッドが UI スレッドからのみ呼び出せるように設計されている場合、これで十分です。

    /// <summary>
    /// Begins a demonstration drawing of the asterism.
    /// </summary>
    public async Task PlayDemoAsync()
    {
        if (this.Sketch != null)
        {
            foreach (var ppc in this.Plots.Select(p => this.TransformPlot(p, this.RenderSize)))
            {
                // For each subsequent stroke plot, we need to start a new figure.
                //
                if (this.Sketch.DrawingPoints.Any())
                    this.Sketch.StartNewFigure(ppc.First().Position);

                foreach (var point in ppc)
                {
                    await Task.Delay(100);

                    this.Sketch.DrawingPoints.Add(point.Position);
                }
            }
        }
    }
于 2013-10-02T09:18:01.313 に答える