J'ai une opération à long terme qui doit être effectuée dans le fil de l'interface utilisateur (implique des éléments d'interface utilisateur qui ne peuvent pas être gelés). Je souhaite afficher un indicateur occupé avant d'exécuter l'opération.
busyIndicator.Visibility = Visibility.Visible; await Task.Yield(); LongRunningMethod();
3 Réponses :
Assumer votre méthode de course longue n'est pas sur une note latérale, vous devez faire attention avec ASYNC CODE> Vous devriez pouvoir l'appeler à l'intérieur de la tâche
code> et
attendre code> le résultat, voire Meilleure utilisation
taskfactory.startnetw code> et transmettre
tasseCreateOptionS.Longrunning code>.
Tâche.yield code> car dans certains scénarios tels que avec
Windowsforms code> la tâche planifiée sur la synchronisation code> a une priorité plus élevée que de repeindre la fenêtre afin que vous puissiez créer votre interface utilisateur. Non réactif si vous appelez à plusieurs reprises
Tâche.yield code>, par exemple dans une boucle omnibue. p> p>
Les mêmes que ci-dessus: TaskFactory.StartNew () exécutera la méthode dans un autre fil et je dois l'exécuter dans le même fil.
Peut-être que vous pouvez simplement appuyer sur les appels de blocage dans un autre thread par en attente code> d'autres méthodes?
Ceci est assez trivial lorsque vous apprenez à asynchroniser et à attendre le travail. Vous pouvez lire à propos de ce sur MSDN
Votre problème est que vous Ne démarrez jamais de travail asynchrone - Essayez ceci: p> Tâche.yield code> est déjà appelé à partir du contexte de l'UI et ne fera rien. P>
async Task MyProcess() //the Task is returned implicitly
{
busyIndicator.Visibility = Visibility.Visible;
await LongRunningMethod(); //the work here is done in a worker thread
busyIndicator.Visibility = Visibility.Collapsed; //this line executes back on the ui context
}
Task LongRunningMethod() //the Async suffix is a convention to differentiate overloads that return Tasks
{
var result1 = await Task.Run(() => /* do some processing */ ); //we are actually starting an asynchronous task here.
//update some ui elements here
var result2 = await Task.Run(() => /* do some more processing */ );
//update some ui elements here
}
Création d'une méthode async code> avec un nom se terminant dans
async code> qui appelle simplement la tâche
est un anti-motif, car la plupart
async code> méthodes n'utilisez pas de fil tandis que
tâche.run code> est donc un peu trompeur
Pour autant que je sache, la tâche.Run () exécutera la méthode dans un autre fil. Comme je l'ai mentionné, je ne peux pas exécuter longrunningmethod dans un autre fil (car il utilise des éléments d'interface utilisateur).
@Nedstoyanov dans cet exemple longRunningMethodasync code> n'est pas un
async code> méthode. Si vous avez eu deux méthodes avec les mêmes paramètres, mais on renvoie une tâche, le suffixe vous permet de compiler. Vous devriez le prendre avec l'équipe de design de Microsoft. Sans doute, vous devriez avoir deux surcharges, mais ce modèle m'a permis de montrer l'utilisation commune
async / attendre code> sans modifier la méthode des travailleurs existante (qui peut être immuable dans son code). Ne sois pas un hather chère! ;)
@AlekseysHubin peut LongRunningMethod Code> être modifié pour ressembler à
MyProcess () code> comme ci-dessus? Ce modèle est la bonne façon de faire fonctionner le travail asynchrone et de mettre à jour le sans geler l'interface utilisateur.
async code> peut être imbriqué.
@Gusdor, certainement pas un haineux, mentionnant simplement ce que j'ai appris des autres. Désolé s'il est tombé sur le mauvais moyen, ce n'était certainement pas prévu de cette façon
Si vous souhaitez casser l'exécution de la méthode UI, vous devez utiliser quelque chose comme (non testé) p> async code> /
attendre code>.
busyIndicator.Visibility = Visibility.Visible;
await Task.Run(() => await Task.Delay(1)); // here method will exit and repaint will occurs
LongRunningMethod();
busyIndicator.Visibility = Visibility.Collapsed;
Merci! Bien que cela semble être un piratage, mais de toute façon cela fonctionne. Je pense que je vais aller avec votre solution pour l'instant. Ne marquera pas comme réponse au cas où quelqu'un conseillera de manière plus simple.
J'ai eu une erreur de compilateur sur l'attente avant la tâche.delay (). La suppression de cela a résolu l'erreur et fonctionne comme prévu.
Où utilisez-vous TPL?
@ l3arnon ne comprend pas. Qu'entendez-vous par «où»?
Le premier échantillon de code n'utilise pas TPL. Vous demandez comment le faire en utilisant TPL. Comment est liée au TPL?
@ L3arnon ne vous attend pas / async et des pièces de tâches de TPL?
@Alekseyshubin
Tâche.yield code> ne crée pas strictement ce que vous comprenez comme une tâche
code>
@Gusdor ok peut-être que j'ai mal compris la façon dont la tâche.yield () fonctionne. De la description de MSDN, je pensais que cela affiche simplement le reste de la méthode du contexte de synchronisation. Exactement ce dont j'ai besoin, sauf que je dois le placer avec une faible priorité, pour vous assurer que le repeinte de l'interface utilisateur se produit devant elle.
Est-ce une application Windows Forms ou WPF?
Application @gusdor WPF
Vous devez diviser toute opération de course longue impliquant des mises à jour de l'interface utilisateur dans les sous-tâches. Si longtemps en cours d'exécution, appelez les pièces que vous pouvez décharger sur un fil d'arrière-plan puis mettre à jour l'interface utilisateur, peut-être via l'interface
iprogress code>.