RunAsync - Wie kann ich erwarten den Abschluss der Arbeit auf dem UI-thread?
Beim warten auf Dispatcher.RunAsync
die Fortsetzung tritt auf, wenn die Arbeit geplant ist, und nicht, wenn die Arbeit abgeschlossen hat. Wie kann ich erwarten, die Arbeit abschließen?
Bearbeiten
Meiner ursprünglichen Frage angenommen die vorzeitige Fortsetzung war bedingt durch das design der API, also hier die eigentliche Frage.
Beim warten auf Dispatcher.RunAsync
unter Verwendung einer asynchronen Delegaten, mit await
innerhalb der Delegat-code, der Fortsetzung tritt auf, wenn die await
aufgetreten ist, nicht, wenn die Arbeit abgeschlossen hat. Wie kann ich erwarten, die Arbeit abschließen?
Edit 2
Einen Grund, müssen Sie möglicherweise die Versendung der Arbeit, die bereits auf dem UI-thread zu umgehen subtile timing und layout-Probleme. Es ist durchaus üblich für Werte der Größe und Position von Elementen in der visuellen Struktur, um in Fluss und Planung der Arbeit für eine spätere iteration der Benutzeroberfläche helfen können.
- Dies ist nicht genau richtig. Die Fortsetzung tritt auf, wenn die lambda zurück. Und wenn die lambda ist eigentlich
async void
, das ist, bevor Sie es tatsächlich abgeschlossen ist. Aber wartenRunAsync()
funktioniert gut für synchrone lambdas. - Ich dachte auch, das könnte der Fall sein, aber ich konnte nicht finden, keine Dokumentation, Wann
RunAsync
soll zurückkehren.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Fand ich den folgenden Vorschlag über eine Microsoft github-repository: Wie warten auf einen UI-Aufgabe gesendet, die von einem hintergrund-thread.
Setup
Definieren diese Erweiterung-Methode für die
CoreDispatcher
:Sobald Sie das tun, ist alles was Sie tun müssen, ist die neue
RunTaskAsync
Methode, um Ihre hintergrund-task warten, die auf der Benutzeroberfläche arbeiten.Beispiel
Let ' s pretend, dass dies die Methode, die laufen muss in dem UI-thread. Achten Sie auf die debug-Anweisungen, die helfen, Folgen dem Fluss:
Zu erwarten, dass von den hintergrund-thread ist dies, wie würden Sie
RunTaskAsync
:Die Ausgabe sieht dann wie folgt aus:
Ihre Frage geht davon aus, dass Sie zeitgesteuert verarbeiten möchten (und warten) Arbeit auf einem UI-thread von einem hintergrund-thread.
Finden Sie in der Regel Ihr code ist viel sauberer und einfacher zu verstehen (und es wird definitiv mehr tragbar), wenn Sie die UI werden die "master" - und die hintergrund-threads werden die "Sklaven".
So, anstatt einen hintergrund-thread
await
eine operation für den UI-thread zu tun (mit der peinlichen und unportabelDispatcher.RunAsync
), müssen Sie den UI-threadawait
einige-Vorgang für den hintergrund-thread zu tun (mit dem tragbaren, made-for-asyncTask.Run
).async
/await
mehr natürlich, als deine Lösung, die keine Ereignisse verwenden, oder warten Sie Griffen an alle.RunAsync()
für?RunAsync
dann wird der Anruf zurück, mit derTask
nur dann, wenn seine komplette. Ich brauche, um wieder eineTask
so schnell wie möglich, damit der Anrufer kann auf ihn warten. Ich kann nicht einfach mit einem richtigenTask
da gibt es eine Menge Zeug, dass ich die Interaktion mit, das erlaubt nur den Zugriff aus dem UI-thread, was bedeutet, dass die Koordination mitRunAsync
wieder (keine synchronenRun
). Ich habe effektiv stellte sich einige UI-arbeiten in einemTask
, die ebenso wie erwartbaren, ist auch schöner als der Umgang mit events und callbacks. Ich denke, für dieses problem (alle verursacht durch dieDelay
), das ist die einfachste Lösung.Task
nur, wenn Ihre komplette" Das ist nicht, wie async-Methoden arbeiten. Es würde keinen Sinn machen, warum sollten solche Methoden zurückTask
in den ersten Platz?RunAsync
hier, seit Ihrer Berufung code läuft auf dem UI-thread; eine einfacheasync Task
Methode sollte ausreichen. Das fühlt sich ein bisschen wie ein "XY" - Gespräch; wenn Sie uns eine übergeordnete problem, das wir finden können, eine bessere übergeordnete Lösung. Wenn ich erklärte, dass ich benutzt, so zu denken, ich spreche von Jahrenasync
Erfahrung und ~50 Projekte. E. g. meine Fortschritte reporting verwendet, um wie folgt Aussehen aber jetzt sieht so aus.async Task
ist korrekt für eine UI-nur erwartbaren Methode. Btw, ich stellte diese auf SO zu zeigen, eine bestimmte Technik (mit TCS). Ich bevorzuge die QA-format auf meinem blog, da es beteiligen sich die anderen Programmierer im Gespräch. Ich erwarte nicht, dass der Ansatz in Frage gestellt werden.TaskAwaiter
- und extension-Methode als ein anderer Weg, dies zu tun, dann ist das wirklich cool +1Können Sie wickeln Sie den Aufruf
RunAsync
im eigenen asynchrone Methode kann abgewartet werden und die Kontrolle der Erledigung der Aufgabe und damit die Fortsetzung warten die Anrufer selbst.Seit async-await, zentriert auf die
Task
geben, müssen Sie orchestrieren das arbeiten mit diesem Typ. Jedoch in der Regel einenTask
Zeitpläne selbst laufen auf einem threadpool-thread und so kann es nicht verwendet werden, um Zeitplan-Benutzeroberfläche arbeiten.Jedoch die
TaskCompletionSource
Art wurde erfunden, um fungieren als eine Art Puppenspieler zu einer ungeplantenTask
. In anderen Worten, eineTaskCompletionSource
können, erstellen Sie ein dummy -Task
ist nicht geplant, etwas zu tun, aber über Methoden auf dieTaskCompletionSource
können angezeigt werden Ausführung und Vollendung, wie ein normaler job.Diesem Beispiel sehen.
Beachten: die wichtigste Arbeit auf dem UI-thread ist nur einige Linien gezogen, die auf dem Bildschirm alle 100ms.
Einen
TaskCompletionSource
erstellt, wie die puppet master. Suchen Sie in der Nähe des Ende und Sie werden sehen, dass esTask
Eigenschaft, die an den Aufrufer zurückgegeben wird. RückkehrTask
erfüllt der Compiler braucht, und macht die Methode erwartbaren und asynchron.Jedoch die
Task
ist nur eine Marionette, ein proxy für die tatsächliche Arbeit in den UI-thread.Sehen, wie in der Haupt-UI-delegate-ich benutze die
TaskCompletionSource.SetResult
Methode, um Kraft, ein Ergebnis in derTask
(da an den Aufrufer zurückgegeben) und zu kommunizieren, dass die Arbeit beendet ist.Wenn es ein Fehler ist, ich benutze
SetException
zu 'ziehen Sie eine andere Zeichenfolge' und machen es scheinen, dass eine Ausnahme hat gequasselt-bis in die PuppeTask
.Den async-await-subsystem kennt es nicht anders und so funktioniert wie man es erwarten würde.
Bearbeiten
Als Aufforderung durch svick, wenn die Methode wurde entwickelt, aufrufbar sein, nur vom UI-thread, dann würde dies ausreichen:
try
alsasync Task
lambda.Task
für diese, aber es ist wahrscheinlich die vernünftigste Wahl.Einen schönen Weg zur Arbeit in die saubere Art und Weise @StephenCleary schlägt sogar, wenn Sie von einem worker-thread aus irgendeinem Grund, ist die Verwendung eines einfachen helper object. Mit dem Objekt unten können Sie code schreiben:
In Ihrer App."OnLaunched" Sie haben, initialisieren Sie das Objekt:
Die Theorie, die hinter den code unten finden Sie eine erwarten Sie nichts;
async
-await
gab es eine Methode, dies zu tun. Aber es wurde entfernt, weil auf diese Weise betrachtet, ist eine schlechte Praxis.