RunAsync - Comment puis-je attendre la fin des travaux sur le thread de l'INTERFACE utilisateur?
En attente de Dispatcher.RunAsync
la poursuite se produit lorsque le travail est prévu, non pas lorsque le travail est terminé. Comment puis-je attendre le travail de remplir?
Modifier
Ma question initiale a assumé le prématuré de continuation a été causé par la conception de l'API, voici donc la vraie question.
En attente de Dispatcher.RunAsync
à l'aide d'un asynchrones délégué, à l'aide de await
au sein du délégué du code, la poursuite se produit lorsque le await
est rencontré, non pas lorsque le travail est terminé. Comment puis-je attendre le travail de remplir?
Edit 2
Une raison, vous devrez peut-être de répartition du travail qui est déjà sur le thread de l'INTERFACE utilisateur est de contourner subtile calendrier et les problèmes d'implantation. Il est assez commun pour les valeurs de tailles et positions des éléments dans l'arborescence visuelle en mouvement et d'établissement du programme de travail pour une version ultérieure de l'INTERFACE utilisateur peut aider.
async void
, c'est avant qu'il se termine en réalité. Mais en attendant RunAsync()
fonctionne parfaitement synchrone lambdas.J'ai aussi pensé que ce pourrait être le cas, mais je ne pouvais pas trouver toute la documentation quand
RunAsync
est censé y retourner.OriginalL'auteur Luke Puplett | 2013-10-02
Vous devez vous connecter pour publier un commentaire.
J'ai trouvé la suggestion suivante sur un Microsoft github: Comment attendent une INTERFACE utilisateur de la tâche envoyée à partir d'un thread d'arrière-plan.
Installation
Définir cette méthode d'extension pour le
CoreDispatcher
:Une fois que vous avez tout ce que vous devez faire est d'utiliser le nouveau
RunTaskAsync
méthode pour avoir votre tâche de fond vous attendent sur l'INTERFACE de travail.Exemple d'utilisation
Faisons semblant de croire que c'est la méthode qui doit s'exécuter dans le thread de l'INTERFACE utilisateur. Prêter attention aux instructions de débogage, ce qui aidera à suivre le flux:
À attendre de votre thread d'arrière-plan, c'est comment vous pouvez l'utiliser
RunTaskAsync
:La sortie ressemble alors à ceci:
Merci d'avoir répondu!
Comment faire pour transférer les paramètres de "ShowMessageAsync"?comme:ShowMessageAsync(string data)
Merci pour la solution!
OriginalL'auteur Mike
Votre question est en supposant que vous voulez programmer (et attendre) travail sur un thread d'INTERFACE utilisateur de un thread d'arrière-plan.
Vous pourrez généralement trouver votre code est beaucoup plus propre et plus facile à comprendre (et ce sera certainement plus portable) si vous avez la de l'INTERFACE utilisateur être le "maître" et les threads d'arrière-plan d'être les "esclaves".
Donc, au lieu d'avoir un thread d'arrière-plan
await
une opération pour le thread d'INTERFACE utilisateur (à l'aide de l'étrange et portablesDispatcher.RunAsync
), vous aurez le thread d'INTERFACE utilisateurawait
une opération pour le thread d'arrière-plan pour le faire (en utilisant le portable, asyncTask.Run
).Mon point est que c'est le signe d'une plus fragile de la conception. A un moment j'ai souvent eu à faire cela, mais une fois que j'ai inversé cette logique, mon design est devenu beaucoup plus propre. Permettant le thread d'INTERFACE utilisateur pour conduire la logique embrasse
async
/await
plus naturellement que votre solution et de ne pas utiliser les événements ou attendre gère tout.Je pense que vous êtes en essayant de répondre à une question sur les pommes avec une réponse sur les oranges. Il y a un problème très spécifique ici: savoir quand cette INTERFACE de travail est terminée. Cette INTERFACE de travail est à l'intérieur d'une INTERFACE utilisateur personnalisée de contrôle, et il en est ainsi pour orchestrer ses mouvements. Pour dire la vérité, ça se passe sur le thread d'INTERFACE utilisateur à l'intérieur d'un contrôle. C'est juste une façon d'utiliser asynchrone-vous attendent pour orchestrer une série de travaux qui doit être fait. Votre point de vue sur la conduite des tâches de fond du thread d'INTERFACE utilisateur est correct en général, et de la façon dont je travaille, mais ce n'est pas applicable ici. Il ne suffit pas à résoudre ce problème.
Parfois, la solution à un problème très spécifique est de faire quelque chose de complètement différent, aussi connu comme XY problème.
Non, il n'est pas. Voir le début de la attendre quoi que ce soit;.
OriginalL'auteur Stephen Cleary
Vous pouvez encapsuler l'appel à
RunAsync
dans votre propre méthode asynchrone qui peut être attendu et de contrôle de l'achèvement de la tâche et donc la suite de l'attente des appelants vous-même.Depuis asynchrone attendent est centrée sur le
Task
type, vous devez d'orchestrer le travail à l'aide de ce type. Cependant, généralement unTask
horaires de lui-même pour s'exécuter sur un pool de threads thread et donc il ne peut pas être utilisé pour programmer l'INTERFACE utilisateur de travail.Cependant, la
TaskCompletionSource
type a été inventé pour agir comme une sorte de marionnettiste à un imprévuTask
. En d'autres termes, unTaskCompletionSource
pouvez créer un mannequinTask
qui n'est pas prévu de faire quoi que ce soit, mais par l'intermédiaire des méthodes sur laTaskCompletionSource
semblent être en cours d'exécution et l'achèvement comme un travail normal.Voir cet exemple.
Remarque: les principaux travaux en cours sur le thread d'INTERFACE utilisateur est juste quelques lignes dessinées sur l'écran de toutes les 100ms.
Un
TaskCompletionSource
est créé comme le puppet master. Regardez près de la fin et vous verrez qu'il a uneTask
propriété qui est retournée à l'appelant. De retourTask
satisfait aux compilateurs besoins et rend la méthode awaitable et asynchrone.Cependant, la
Task
est juste une marionnette, un proxy pour le travail en cours dans le thread de l'INTERFACE utilisateur.Voir comment dans cette INTERFACE principale délégué-je utiliser le
TaskCompletionSource.SetResult
méthode pour forcer un résultat dans laTask
(depuis retourné à l'appelant) et de communiquer que le travail est terminé.Si il y a une erreur, j'utilise
SetException
à "tirer une autre chaîne de caractères" et de le faire apparaître comme une exception a barboter dans la marionnetteTask
.Async-attendent sous-système sait pas différente, et il fonctionne comme vous le souhaitez.
Modifier
Comme demandé par le svick, si la méthode a été conçue pour être appelée uniquement à partir de la thread de l'INTERFACE utilisateur, alors cela devrait suffire:
Yep. C'est ce que l'assurance qualité est pour.
Si vous faites cela, souvent, il serait judicieux de créer une méthode d'assistance, ce qui permettrait de prendre le code qui est exécuté à l'intérieur de la
try
comme unasync Task
lambda.Aussi, vous n'avez pas à utiliser
Task
pour cela, mais c'est probablement le plus raisonnable.OriginalL'auteur Luke Puplett
Une belle façon de travailler le propre @StephenCleary suggère même si vous devez démarrer à partir d'un thread pour une raison quelconque, est d'utiliser un simple objet d'assistance. Avec l'objet ci-dessous, vous pouvez écrire du code comme ceci:
Dans votre Application.OnLaunched vous devez les initialiser l'objet:
La théorie derrière le code ci-dessous vous pouvez trouver à attendre quoi que ce soit;
async
-await
, il y avait une méthode pour ce faire. Mais il a été supprimé, parce que cette façon de faire est considéré comme une mauvaise pratique.il peut être considéré comme une mauvaise pratique, mais parfois (comme lorsque vous voulez faire liées à l'INTERFACE utilisateur de choses dans le SplashScreen.Rejeté de l'événement), vous n'avez pas le choix. Dans l'exemple que j'ai mentionné, j'ai découvert que le SplashScreen.Rejeté événement ne s'exécute PAS sur le thread de l'INTERFACE utilisateur, ce qui signifie que les choses que vous attendez le gestionnaire est hors-limites-sauf si vous utilisez cette classe pour le forcer à exécuter le reste sur le thread de l'INTERFACE utilisateur.
OriginalL'auteur Marcel W