Pourquoi ne pas contrôler la mise à jour / actualisation en cours de processus?

J’ai un formulaire Windows (C # .NET) avec un statusLabel que je n’arrive pas à mettre à jour au milieu d’un processus dans les méthodes du gestionnaire d’événements. Mon code ressemble à ceci …

void Process_Completed(object sender, EventArgs e) { ssortingng t = "Process is finished!"; this.Invoke(new StatusLabelUpdator(updateStatusLabel), new object[] { t }); } void Process_Started(object sender, EventArgs e) { ssortingng t = "Process has begun"; this.Invoke(new StatusLabelUpdator(updateStatusLabel), new object[] { t }); } private delegate void StatusLabelUpdator(ssortingng text); private void updateStatusLabel(ssortingng text) { StatusLabel1.Text = text; statusSsortingp1.Invalidate(); statusSsortingp1.Refresh(); statusSsortingp1.Update(); } 

Lorsque j’exécute le code, une fois le processus démarré, la méthode Process_Started est déclenchée et quelques secondes plus tard, la méthode Process_Completed est déclenchée. Pour une raison quelconque, je ne peux pas obtenir l’étiquette d’état pour afficher “Processus commencé”. Il n’affiche que “Le processus est terminé!”. Comme vous pouvez le constater, j’ai essayé d’invalider, d’actualiser et de mettre à jour la bande d’état contenant l’étiquette mais sans succès. Je ne peux pas appeler update / refresh / invalidate sur le label de statut lui-même car ces méthodes ne lui sont pas disponibles. Qu’est-ce que je fais mal?

INFO AJOUTÉE:

Le “processus” est démarré par un clic sur le formulaire qui appelle une méthode dans une classe séparée qui ressemble à ceci:

 public void DoSomeProcess() { TriggerProcessStarted(); System.Threading.Thread.Sleep(2000); // For testing.. TriggerProcessComplete(); } 

et dans les méthodes TriggerProcessxxxx, je déclenche les événements à l’aide de ce code …

 var EventListeners = EH.GetInvocationList(); //EH is the appropriate EventHandler if (EventListeners != null) { for (int index = 0; index < EventListeners.Count(); index++) { var methodToInvoke = (EventHandler)EventListeners[index]; methodToInvoke.BeginInvoke(this, EventArgs.Empty, EndAsyncEvent, new object[] { }); } } 

Enfin, j’ai ajouté Application.DoEvents() à la méthode updateStatusLabel mais cela n’a pas aidé. J’obtiens toujours le même résultat. Voici ma méthode de mise à jour.

 private void updateStatusLabel(ssortingng text) { StatusLabel1.Text = text; statusSsortingp1.Refresh(); Application.DoEvents(); } 

Donc, je suppose que le “traitement” a lieu sur le thread d’interface utilisateur, mais Eventhandler est invoqué sur son propre thread, qui appelle ensuite la mise à jour du contrôle sur le thread d’interface utilisateur. Est-ce une façon stupide de faire les choses? Remarque: la classe qui contient la méthode DoSomeProcess () se trouve dans une bibliothèque de classes .NET distincte à laquelle je fais référence.

Si vous effectuez le traitement sur le thread d’interface utilisateur, il ne pourra rien faire d’autre (comme redessiner les étiquettes mises à jour) pendant l’exécution du traitement. Ainsi, par exemple, si le traitement est en cours parce que l’utilisateur a cliqué sur un bouton et qu’il est déclenché par le gestionnaire de clic du bouton (sans le placer explicitement sur un autre thread), il s’exécute sur le thread d’interface utilisateur. Même si vous mettez à jour le texte de l’étiquette, celle-ci n’est pas dessinée tant qu’elle n’a pas reçu de message de peinture. À ce stade, votre traitement est probablement occupé.

La solution consiste à effectuer un traitement de longue durée sur un thread séparé . Le hack (IMHO) consiste à utiliser Application.DoEvents pour permettre au thread d’interface utilisateur d’effectuer des opérations d’interface utilisateur pendant votre traitement. Si vous mettez l’un de ceux-ci après la mise à jour de l’étiquette et avant de commencer votre traitement, les chances sont assez élevées, l’étiquette sera repeinte. Toutefois, lors du traitement, aucun événement de peinture supplémentaire ne peut être traité (ce qui entraîne des fenêtres à moitié dessinées lorsque quelqu’un déplace une autre fenêtre d’application sur votre application et inversement, etc.). D’où mon appelant un bidouillage (même si, euh, euh, j’ai été connu pour le faire :-)).

Modifier la mise à jour en fonction de vos modifications:

Donc, je suppose que le “traitement” a lieu sur le thread d’interface utilisateur, mais Eventhandler est appelé sur son propre thread …

Je suppose que DoSomeProcess est déclenché à partir du thread d’interface utilisateur (par exemple, en réponse directe à un clic de bouton ou similaire). Si oui, alors oui, votre traitement est définitivement sur le fil de l’interface utilisateur. Étant TriggerProcessStarted que TriggerProcessStarted déclenche votre rappel de manière asynchrone via BeginInvoke , vous ne savez pas quand il sera exécuté, mais dans tous les cas, votre code est immédiatement lancé dans le traitement, ne cédant jamais, de sorte que personne d’autre ne pourra saisir ce thread. Etant donné qu’il s’agit du thread d’interface utilisateur, l’appel du délégué sera bloqué lors de l’appel de l’appel Invoke définissant le texte du libellé. Il devra ensuite attendre que le thread de l’interface utilisateur (dont le traitement est occupé). (Et cela suppose que ce soit programmé sur un fil différent; je ne pourrais pas me convaincre à 100% de toute façon, car Microsoft a deux BeginInvoke différents, ce que l’un des concepteurs de l’IIRC a reconnu être une idée vraiment stupide. depuis que je me suis battu avec ce genre de choses)

Si vous faites les appels TriggerProcessStarted à vos rappels synchrones, tout devrait bien se passer. Mais idéalement, planifiez le traitement (si ce n’est pas l’interface utilisateur) sur son propre thread.