Utilisation de L'Application.DoEvents()

Peut Application.DoEvents() être utilisé en C#?

Est cette fonction de manière à permettre à l'interface graphique pour rattraper le reste de l'application, de la même manière que VB6 DoEvents ?

237
demandé sur Daniel B 2011-03-03 17:08:31

9 réponses

Hmya, la pérennité de la mystique de la fonction DoEvents(). Il y a eu une énorme réaction contre, mais personne n'explique jamais vraiment pourquoi c'est "mauvais". Le même genre de sagesse que "ne mute pas une structure". Pourquoi le runtime et le langage supportent la mutation d'une struct si c'est si mauvais? Même raison: vous vous tirez dans le pied, si vous ne le faites pas droit. Facilement. Et le faire correctement exige de savoir exactement ce qu'il fait, qui dans le cas de DoEvents() n'est certainement pas facile à analyser.

tout de suite: presque tous les programmes Windows Forms contiennent en fait un appel à DoEvents(). Il est habilement déguisé, cependant avec un nom différent: ShowDialog(). C'est DoEvents() qui permet à une boîte de dialogue d'être modale sans geler le reste des fenêtres de l'application.

la plupart des programmeurs veulent utiliser DoEvents pour empêcher leur interface utilisateur de geler lorsqu'ils écrivent leur propre boucle modale. Il il envoie des messages Windows et reçoit toutes les requêtes de peinture. Le problème, toutefois, est qu'il n'est pas sélective. Il n'envoie pas seulement des messages de peinture, il délivre aussi tout le reste.

et il y a un ensemble de notifications qui causent des problèmes. Ils viennent d'environ 3 pieds devant le moniteur. L'utilisateur peut par exemple fermer la fenêtre principale pendant que la boucle qui appelle DoEvents() est en cours d'exécution. Qui fonctionne, l'interface utilisateur est allé. Mais votre le code ne s'est pas arrêté, il exécute toujours la boucle. C'est un mauvais. Très, très mauvais.

il y a plus: l'utilisateur peut cliquer sur le même élément de menu ou le même bouton qui fait démarrer la même boucle. Maintenant vous avez deux boucles imbriquées exécutant DoEvents (), la boucle précédente est suspendue et la nouvelle boucle part de zéro. Cela pourrait fonctionner, mais le garçon les chances sont minces. Surtout quand la boucle imbriquée se termine et que la boucle suspendue reprend, essayant de finir un travail qui était déjà compléter. Si cela ne fait pas de bombe avec une exception, alors sûrement les données sont brouillées tout à fait en enfer.

retour à ShowDialog(). Il exécute DoEvents (), mais notez qu'il fait autre chose. Il désactive toutes les fenêtres de l'application , autre que la boîte de dialogue. Maintenant que le problème de 3 pieds est résolu, l'utilisateur ne peut rien faire pour gâcher la logique. Les deux modes de défaillance "fermer la fenêtre" et "recommencer le travail" sont résolus. Ou pour le dire d'une autre façon, il n'y a aucun moyen pour l'utilisateur de faire votre programme d'exécuter du code dans un ordre différent. Il s'exécutera de façon prévisible, tout comme il l'a fait lorsque vous avez testé votre code. Cela rend les dialogues extrêmement ennuyeux; qui ne déteste pas avoir un dialogue actif et ne pas pouvoir copier et coller quelque chose d'une autre fenêtre? Mais c'est le prix.

qui est ce qu'il faut pour utiliser DoEvents en toute sécurité dans votre code. Paramétrer la propriété Enabled de tous vos formulaires à false est rapide et efficace façon à éviter les problèmes. Bien sûr, aucun programmeur n'aime vraiment faire ça. Et ne le fait pas. C'est pourquoi vous ne devriez pas utiliser DoEvents(). Vous devriez utiliser des fils. Même s'ils vous donnent un arsenal complet de façons de tirer votre pied dans des façons colorées et impénétrables. Mais avec l'avantage que vous tirez seulement votre propre pied; il ne sera pas (typiquement) laisser l'utilisateur tirer le sien.

les versions suivantes de C# et VB.NET fournira une arme différente avec la nouvelle attente et async mot. Inspiré en petite partie par les problèmes causés par les événements et les threads mais en grande partie par la conception API de WinRT que nécessite vous de garder votre UI à jour alors qu'une opération asynchrone est en cours. Comme la lecture à partir d'un fichier.

427
répondu Hans Passant 2016-10-23 10:20:55

c'est possible, mais c'est un piratage.

Voir Est La Fonction DoEvents Mal? .

Directement la page MSDN que thedev référencé:

appeler cette méthode provoque le courant fil à suspendre pendant que tout les messages de fenêtre d'attente sont traités. Si un message provoque un événement déclenchée, puis autre les zones de votre le code de l'application peut s'exécuter. Cela peut la cause de votre demande d'admission comportements inattendus qui sont difficile à déboguer. Si vous effectuez opérations ou calculs qui nécessitent depuis longtemps, il est souvent préférable d' effectuer ces opérations sur un nouveau fil. Pour plus d'informations sur programmation asynchrone, voir Aperçu De La Programmation Asynchrone.

donc Microsoft met en garde contre son utilisation.

Aussi, I considérez-le comme un hack parce que son comportement est imprévisible et sujet aux effets secondaires (cela vient de l'expérience d'essayer D'utiliser DoEvents au lieu de faire tourner un nouveau fil ou d'utiliser le travailleur d'arrière-plan).

il n'y a pas de machismo ici - si cela fonctionnait comme une solution robuste je serais tout sur elle. Cependant, essayer D'utiliser DoEvents dans .NET ne m'a causé que de la douleur.

27
répondu RQDQ 2017-05-23 12:18:06

Oui, il y a une méthode DoEvents statique dans la classe D'Application du système.Windows.Les formes de l'espace de noms. Système.Windows.Forme.Application.DoEvents () peut être utilisé pour traiter les messages en attente dans la file d'attente sur le thread de L'interface utilisateur lors de l'exécution d'une tâche de longue durée dans le thread de l'interface utilisateur. Cela a l'avantage de faire en sorte que L'assurance-chômage semble plus réceptive et non "verrouillée" pendant qu'une longue tâche est en cours. Cependant, ce n'est presque toujours pas la meilleure façon de faire les choses. Selon Microsoft calling DoEvents"...provoque la suspension du thread courant pendant que tous les messages de fenêtre d'attente sont traités."Si un événement est déclenché, il y a un risque de bogues imprévus et intermittents qui sont difficiles à repérer. Si vous avez une tâche vaste, il est beaucoup mieux de le faire dans un fil séparé. Exécuter de longues tâches dans un thread séparé permet de les traiter sans interférer avec L'interface utilisateur qui continue à fonctionner en douceur. Regardez ici pour plus de détails.

ici est un exemple d'utilisation de DoEvents; notez que Microsoft fournit également une mise en garde contre son utilisation.

23
répondu Bill W 2017-06-26 19:23:02

D'après mon expérience, je conseillerais une grande prudence avec DoEvents in .NET. J'ai connu des résultats très étranges lors de L'utilisation de DoEvents dans un TabControl contenant DataGridViews. D'autre part, si vous êtes face à un petit formulaire avec une barre de progression, alors qu'il pourrait être OK.

la ligne de fond est: si vous allez utiliser DoEvents, alors vous devez le tester complètement avant de déployer votre application.

14
répondu Craig Johnston 2013-11-20 14:54:32

Oui.

cependant, si vous devez utiliser Application.DoEvents , il s'agit principalement d'une indication d'une mauvaise conception de l'application. Peut-être voudriez-vous faire un peu de travail dans un fil séparé à la place?

10
répondu Frederik Gheysels 2016-09-24 13:59:08

j'ai vu beaucoup d'applications commerciales, en utilisant le"DoEvents-Hack". Surtout quand le rendu entre en jeu, je le vois souvent:

while(running)
{
    Render();
    Application.DoEvents();
}

ils connaissent tous le mal de cette méthode. Cependant, ils utilisent le hack, parce qu'ils ne connaissent aucune autre solution. Voici quelques approches prises à partir d'un post de blog par Tom Miller :

  • définir votre formulaire pour avoir tous les dessins se produisent dans WmPaint, et faites votre rendu là. Avant la fin de la méthode OnPaint, assurez-vous de faire cela.Invalider (); ceci provoquera le redémarrage immédiat de la méthode OnPaint.
  • P/Invoke dans l'API Win32 et appel PeekMessage/TranslateMessage/DispatchMessage. (Doevents réellement fait quelque chose de similaire, mais vous pouvez le faire sans les allocations).
  • écrivez votre propre classe de formulaires qui est un petit emballage autour de CreateWindowEx, et vous donner le contrôle complet sur la boucle de message. - Décider que la méthode DoEvents fonctionne bien pour vous et s'en tenir à elle.
4
répondu Matthias 2011-12-19 21:59:06

j'ai vu le commentaire de jheriko ci-dessus et j'ai été d'abord d'accord que je ne pouvais pas trouver un moyen d'éviter D'utiliser DoEvents si vous finissez par tourner votre UI fil principal en attente d'un long morceau asynchrone courant de code sur un autre fil à compléter. Mais de la réponse DE Matthias un rafraîchissement simple d'un petit panneau sur mon UI peut remplacer les événements (et éviter un effet secondaire désagréable).

plus de détails sur mon affaire ...

je faisais ce qui suit (comme suggéré ici ) pour s'assurer qu'une barre de progression type splash écran ( Comment afficher un "chargement" superposition... ) mis à jour lors D'une commande SQL de longue durée:

IAsyncResult asyncResult = sqlCmd.BeginExecuteNonQuery();
while (!asyncResult.IsCompleted)  //UI thread needs to Wait for Async SQL command to return
{
      System.Threading.Thread.Sleep(10); 
      Application.DoEvents();  //to make the UI responsive
}

the bad: pour moi, appeler DoEvents signifiait que les clics de souris tiraient parfois sur des formes derrière mon écran d'éclaboussure, même si je l'ai fait le plus haut.

La bonne réponse: Remplacer la DoEvents line avec un simple appel de rafraîchissement à un petit panneau au centre de mon écran splash, FormSplash.Panel1.Refresh() . Les mises à jour de L'interface utilisateur et la bizarrerie de DoEvents dont d'autres ont parlé ont disparu.

3
répondu TamW 2017-05-23 10:31:34

de l'Application.DoEvents peut créer des problèmes, si quelque chose d'autre que le traitement graphique est mis dans la file d'attente de messages.

il peut être utile pour mettre à jour les barres de progression et informer l'utilisateur de la progression dans quelque chose comme la construction de la forme principale et le chargement, si cela prend un certain temps.

dans une application récente que j'ai faite, J'ai utilisé DoEvents pour mettre à jour certaines étiquettes sur un écran de chargement chaque fois qu'un bloc de code est exécuté dans le constructeur de mon MainForm. Dans ce cas, le thread D'UI était occupé à envoyer un e-mail sur un serveur SMTP qui ne supportait pas les appels SendAsync (). J'aurais probablement pu créer un thread différent avec les méthodes Begin() et End() et appelé un Send() à partir de leurs, mais cette méthode est sujette aux erreurs et je préférerais que la forme principale de mon application ne lance pas d'exceptions pendant la construction.

2
répondu Guest123 2014-09-20 16:43:52

consultez la Documentation MSDN pour la méthode Application.DoEvents .

2
répondu thedev 2016-09-24 13:58:14