9
votes

Mettre à jour l'interface utilisateur avant d'exécuter le reste de la méthode

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();


9 commentaires

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 ne crée pas strictement ce que vous comprenez comme une tâche


@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 .


3 Réponses :


1
votes

Assumer votre méthode de course longue n'est pas ASYNC Vous devriez pouvoir l'appeler à l'intérieur de la tâche et attendre le résultat, voire Meilleure utilisation taskfactory.startnetw et transmettre tasseCreateOptionS.Longrunning . xxx

sur une note latérale, vous devez faire attention avec Tâche.yield car dans certains scénarios tels que avec Windowsforms la tâche planifiée sur la synchronisation 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 , par exemple dans une boucle omnibue.


2 commentaires

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 d'autres méthodes?



2
votes

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 - Tâche.yield code> est déjà appelé à partir du contexte de l'UI et ne fera rien. P>

Essayez ceci: 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
}


5 commentaires

Création d'une méthode async avec un nom se terminant dans async qui appelle simplement la tâche est un anti-motif, car la plupart async méthodes n'utilisez pas de fil tandis que tâche.run 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 n'est pas un async 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 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 être modifié pour ressembler à MyProcess () 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 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



11
votes

Si vous souhaitez casser l'exécution de la méthode UI, vous devez utiliser async code> / attendre code>.

quelque chose comme (non testé) p>

busyIndicator.Visibility = Visibility.Visible;
await Task.Run(() => await Task.Delay(1)); // here method will exit and repaint will occurs
LongRunningMethod();
busyIndicator.Visibility = Visibility.Collapsed;


2 commentaires

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.