2009-08-03 10 views
2

J'ai une simple boucle C# foreach, comment puis-je sortir de la boucle quand on appuie sur un bouton? Ce n'est pas dans un thread backgroundWorker donc je ne peux pas utiliser backgroundWorker.CancellationPending.C# Saut de boucle sur la touche Appuyez sur

+1

La boucle foreach est-elle utilisée sur un filetage séparé? ou sur le fil de l'interface utilisateur? – ThePower

+0

La boucle est-elle en cours d'exécution sur un autre thread? – AaronLS

+1

Si la boucle se trouve sur le thread d'interface utilisateur, le gestionnaire d'événements de clic de bouton ne sera pas atteint tant que la fonction contenant la boucle ne sera pas terminée. – ThePower

Répondre

5

Créez un indicateur booléen dans le formulaire. Attachez un gestionnaire d'événements à l'événement click et définissez l'indicateur sur true dans le gestionnaire d'événements.

Vérifiez le drapeau dans la boucle et si c'est vrai, appelez "break". (Une meilleure option serait d'utiliser une boucle while au lieu d'une boucle for avec la vérification de l'indicateur dans la condition while)

Il est évident que la boucle for doit être sur une certaine forme de thread d'arrière-plan, sinon l'interface graphique l'emporte. t être réactif. Si vous ne savez pas comment procéder, consultez le ThreadPool.QueueUserWorkItem ou le BackgroundWorker. Si vous utilisez un BackgroundWorker, vous pouvez utiliser la méthode intégrée CancelAsync() au lieu de coder votre propre drapeau d'annulation. [Edit: Comme indiqué par d'autres (ci-dessous) et discuté plus en profondeur here et here;

vous ne devez soit verrouillage avant d'accéder à la bool ou marquer comme volatile]

[Ne pas oublier de définir l'état correct du drapeau avant de commencer la boucle.]

+4

Évidemment, le drapeau doit être volatile, ou l'accès doit être synchronisé. – EFraim

+3

efraim, pourquoi auriez-vous besoin de synchroniser l'accès à un simple champ bool? L'utilisateur ne peut pas très bien appuyer sur le bouton qui démarre la boucle ET sur le bouton qui l'annule en même temps, n'est-ce pas? –

+0

@EFraim. Je ne suis pas sûr de cela. Je ne pense pas que vous ayez besoin de le verrouiller, car vous ne l'écrivez que d'un endroit (l'événement click button). La boucle for ne fait que la lire, donc même si la lecture et l'écriture se sont produites en même temps, le pire des cas est qu'il lui suffirait d'effectuer une nouvelle itération de boucle avant de s'arrêter. Quelqu'un peut-il confirmer cela? –

4

Voici un sans but bonne solution.

Appelez Application.DoEvents() à chaque itération de votre boucle. Lors d'un clic sur un bouton, définissez une variable sur Vrai et, en boucle, vérifiez cette variable. Si c'est vrai, cassez sinon continuez.

Comme je l'ai dit, ce n'est pas une très bonne solution. Application.DoEvents() peut être très dangereux. La meilleure option ici est d'avoir un fil de fond.

+2

Je suis d'accord. C'est une solution pas si bonne. N'utilisez pas DoEvents. Mettez la boucle for sur un thread d'arrière-plan correctement en utilisant un worker d'arrière-plan ou ThreadPool.QueueUserWorkItem() –

+0

+1 pour quelque chose qui fonctionne réellement, même si c'est une solution plutôt laide qui ne change pas d'échelle ... Vous pouvez ajouter un compteur et appelez DoEvents toutes les n: ièmes itérations pour réduire les pertes de performances. – Guffa

0

Vous pouvez utiliser DoEvents, comme suggéré par Aamir, comme solution rapide.

Pour une solution plus évolutive et maintenable, vous devez déplacer le travail vers un thread séparé. Ensuite, il est plutôt trivial d'avoir un événement de clic sur un bouton pour arrêter la boucle. D'un autre côté, il y a un peu plus de travail pour communiquer le résultat au thread de l'interface utilisateur.

Questions connexes