Comment faire pour exécuter et d'interagir avec un async Tâche à partir d'une interface graphique WPF
J'ai un WPF GUI, où je veux appuyer sur un bouton pour démarrer une tâche de longue haleine sans gel de la fenêtre pour la durée de la tâche. Alors que la tâche est en cours, je voudrais obtenir des rapports sur les progrès, et j'aimerais intégrer un autre bouton qui permet d'arrêter la tâche à tout moment que je choisis.
Je ne peux pas la figure de la bonne façon d'utiliser les async/await/tâche. Je ne peux pas inclure tout ce que j'ai essayé, mais c'est ce que j'ai en ce moment.
Une fenêtre WPF classe :
public partial class MainWindow : Window
{
readonly otherClass _burnBabyBurn = new OtherClass();
internal bool StopWorking = false;
//A button method to start the long running method
private async void Button_Click_3(object sender, RoutedEventArgs e)
{
Task burnTheBaby = _burnBabyBurn.ExecuteLongProcedureAsync(this, intParam1, intParam2, intParam3);
await burnTheBaby;
}
//A button Method to interrupt and stop the long running method
private void StopButton_Click(object sender, RoutedEventArgs e)
{
StopWorking = true;
}
//A method to allow the worker method to call back and update the gui
internal void UpdateWindow(string message)
{
TextBox1.Text = message;
}
}
Et une classe pour le travailleur méthode:
class OtherClass
{
internal Task ExecuteLongProcedureAsync(MainWindow gui, int param1, int param2, int param3)
{
var tcs = new TaskCompletionSource<int>();
//Start doing work
gui.UpdateWindow("Work Started");
While(stillWorking)
{
//Mid procedure progress report
gui.UpdateWindow("Bath water n% thrown out");
if (gui.StopTraining) return tcs.Task;
}
//Exit message
gui.UpdateWindow("Done and Done");
return tcs.Task;
}
}
Cela fonctionne, mais le WPF fenêtre de fonction est toujours bloqué une fois que le travailleur méthode commence.
J'ai besoin de savoir comment organiser la async/await/tâche déclarations pour permettre
A) le travailleur méthode pour ne pas bloquer l'interface
B) laisser les travailleurs de la méthode de mise à jour de l'interface
C) permettre à l'interface pour arrêter l'interrompre et arrêter le travailleur méthode
De l'aide ou des pointeurs sont très appréciées.
OriginalL'auteur Kickaha | 2014-11-23
Vous devez vous connecter pour publier un commentaire.
Rapide astuce:
Explication:
async
etawait
doit être utilisé selon la même méthode.Task.Run
files d'attente une méthode (comme unTask
ouTask<T>
) dans le pool de threads (il utilise/crée un autre thread pour exécuter la tâche)L'exécution attend à
await
pour la fin de la tâche et jette en arrière de ses résultats, sans bloquer le thread principal en raison de laasync
mot clé capacité magique.La magie de
async
mot-clé est qu'il ne pas créer un autre thread. Elle seule permet au compilateur de abandonner et reprendre le contrôle sur cette méthode.Donc
Votre thread principal appelle la
async
méthode (Button_Click_3
) comme une méthode normale et pas de filetage jusqu'à... Maintenant, vous pouvez exécuter une tâche à l'intérieur de laButton_Click_3
comme ceci:ou tout simplement
ou si
ExecuteLongProcedureAsync
a une valeur de retour de typestring
ou tout simplement
La méthode à l'intérieur de la tâche (ou
ExecuteLongProcedureAsync
) s'exécute de manière asynchrone et ressemble à ceci:Note 1:
Task.Run
est plus récente (.NetFX4.5) et la version plus simple deTask.Factory.StartNew
await
est pasTask.Wait()
Note 2:
Sleep
blocs le thread principal, même qu'elle est appelée dans la méthode avecasync
mot-clé.await
empêche la tâche de bloquer le thread principal en raison de laasync
mot-clé.Note 3 (GUI):
Si vous avez accès à GUI de manière asynchrone (à l'intérieur de
ExecuteLongProcedureAsync
méthode), invoquer toute opération qui implique l'accès à l'interface graphique champs:Cependant, Si une tâche est démarrée à la suite d'une propriété a changé de rappel à partir de ce Dernier, il n'est pas nécessaire d'utiliser
Dispatcher.Invoke
car le rappel est exécuté à partir de la thread de l'INTERFACE utilisateur.Les changements de la valeur de feu tiré par INotifyPropertyChanged sont automatiquement placés en arrière sur le répartiteur.
Comment faire pour activer la croix-thread accès
Rappelez-vous,
async
méthode qui s'exécute sur le thread principal. C'est donc valide:Lire plus
MSDN explique
Tâche
MSDN explique
async
async attendent
- les coulissesasync attendent
- FAQVous pouvez également lire un simple fichier asynchrone écrivain de savoir où vous devriez simultanées.
Enquêter sur simultanée de l'espace de noms
Enfin lire ce livre électronique: Patterns_of_Parallel_Programming_csharp
Vous êtes les bienvenus. pour le dossier, il est parfois préférable de dormir la async fil en ajoutant
System.Threading.Thread.Sleep(10);
à la fin de UpdateWindow méthode.Grande réponse. Je voudrais ajouter une option de plus. Si vous liez votre INTERFACE utilisateur d'un objet qui implémente
INotifyPropertyChanged
(généralement appelé ViewModel), vous pouvez modifier les propriétés de l'objet thread asynchrone. WPF databinding mechanizm basculera vers le thread d'INTERFACE utilisateur pour vous.Merci @Liero pour de l'information utile. Je l'ai mis à répondre
OriginalL'auteur Bizhan
Votre utilisation de
TaskCompletionSource<T>
est incorrect.TaskCompletionSource<T>
est un moyen de créer TAP-compatible wrappers pour les opérations asynchrones. Dans votreExecuteLongProcedureAsync
méthode, l'exemple de code est tout le CPU (c'est à dire, intrinsèquement synchrone, pas asynchrone).Donc, c'est beaucoup plus naturel d'écrire
ExecuteLongProcedure
comme une méthode synchrone. C'est aussi une bonne idée d'utiliser des types standard pour des comportements standard, en particulier à l'aide deIProgress<T>
pour le progrès des mises à jour etCancellationToken
pour annulation:Maintenant, vous avez un plus réutilisable type (pas de GUI dépendances) qui utilise les conventions appropriées. Il peut être utilisé en tant que tel:
Le
bool
approche est techniquement faux; il fait des hypothèses erronées sur le .NET modèle de mémoire.Ahh.. oui, juste assez. Pour mettre en œuvre pause Malade, assurez-vous de seralize et enregistrer, puis reprendre l'état de l'enregistrer au lieu de supposer que la persistance quand il y a manifestement ne doit pas être tout. Je vous remercie.
OriginalL'auteur Stephen Cleary
C'est une version simplifiée de la réponse la plus populaire ici par Bijan. Je l'ai simplifié Bijan réponse pour m'aider à penser à travers le problème à l'aide de la belle mise en forme fournie par le Débordement de la Pile.
De lire attentivement et de l'édition de Bijan du post, j'ai enfin compris: Comment attendre méthode asynchrone à remplir?
Dans mon cas, la réponse choisie pour que d'autres post, c'est ce qui m'a finalement conduit à résoudre mon problème:
"Éviter
async void
. Avez vos méthodes de retourTask
au lieu devoid
. Ensuite, vous pouvezawait
."Ma version simplifiée de Bijan (excellent) suit la réponse:
1) Il démarre une tâche à l'aide de async et await:
2) C'est la méthode à exécuter de manière asynchrone:
3) appelez l'opération qui implique une propriété à partir de l'interface graphique:
Ou,
Commentaires de clôture) Dans la plupart des cas, vous disposez de deux méthodes.
Première méthode (
Button_Click_3
) appelle la deuxième méthode et a laasync
modificateur qui indique au compilateur de permettre à enfiler pour cette méthode.Thread.Sleep
dans unasync
méthode bloque le thread principal. mais en attente d'une tâche ne.await
états jusqu'à ce que la tâche est terminée.await
à l'extérieur d'unasync
méthodeDeuxième méthode (
ExecuteLongProcedureAsync
) est emballé dans une tâche et renvoie un génériqueTask<original return type>
objet qui peut être instruit pour être traité de manière asynchrone par l'ajout deawait
avant.Important:
Liero apporté une question importante. Lorsque vous êtes à la Liaison d'un élément à un ViewModel de la propriété, la propriété a changé de rappel est exécuté dans le thread de l'INTERFACE utilisateur. Donc, il n'est pas nécessaire d'utiliser
Dispatcher.Invoke
. Les changements de la valeur de feu tiré par INotifyPropertyChanged sont automatiquement placés en arrière sur le répartiteur.Eric, le remixage les réponses des autres est très encouragée, aussi longtemps que vous le crédit. Le parti libéral de licence (voir "cc by-sa 3.0" dans le pied de page du site) autorise explicitement.
OriginalL'auteur Eric D
Voici un exemple d'utilisation de
async/await
,IProgress<T>
etCancellationTokenSource
. Ce sont les modernes C# et .Net Framework fonctionnalités de la langue que vous devrait être en utilisant. Les autres solutions sont à faire mes yeux saignent un peu.Code
La vue
Le code
OriginalL'auteur Gusdor
Il a été pendant plusieurs années depuis que la question a été posée, mais je pense qu'il est intéressant de noter que la classe BackgroundWorker est conçu précisément pour obtenir A, B et C exigences.
Complète de l'échantillon de référence msdn page: https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs. 110).aspx
Aussi, je ne suis pas sûr que votre commentaire est tout à fait correct tout de même. Voir: stackoverflow.com/questions/12414601/...
Il y a tellement de simultanéité des modèles en c#, qui tous faire parvenir A,B,C
OriginalL'auteur rbenavides