Mon événement Timer se bloque car les événements sont appelés sur un autre thread

J’obtiens le message d’erreur “Opération cross-thread non valide: le contrôle ‘label1’ accessible depuis un thread autre que celui sur lequel il a été créé.” quand je lance ce code:

using System; using System.ComponentModel; using System.Data; using System.Text; using System.Windows.Forms; using System.Timers; namespace WindowsFormsApplication1 { public partial class Form1 : Form { System.Timers.Timer T = new System.Timers.Timer(); public Form1() { InitializeComponent(); T.Elapsed += new ElapsedEventHandler(T_Elapsed); T.Start(); } void T_Elapsed(object sender, ElapsedEventArgs e) { label1.Text = "This will not work"; } } } 

Je pensais que les événements allaient dans le même fil qu’ils étaient déclenchés.

Vous utilisez peut-être le mauvais type de timer. Essayez le minuteur WinForms, il s’exécute sur le fil de l’interface graphique pour ne pas avoir à invoquer Invoke.

Nous avons 3 classes de timer dans NET (Timers.Timer, Threading.Timer et Windows.Forms.Timer), mais seule la classe Windows.Forms a un événement Tick.

Lorsqu’il est utilisé normalement (c.-à-d. Déplacé vers le formulaire au moment du design ou créé dans un code de formulaire), l’événement est en cours d’exécution sur le thread principal et votre problème ne devrait pas se produire.

Il est donc fort probable que vous créiez l’object Timer dans un autre thread, vous devriez probablement éditer votre question pour nous montrer comment / où vous le créez et nous dire si elle se trouve express dans un autre thread.

Bien que la réponse “acceptée” soit techniquement correcte (en ce sens que cela résoudra le problème), cela ne répond pas à la question.

La RÉPONSE est d’utiliser

 void T_Elapsed(object sender, ElapsedEventArgs e) { this.BeginInvoke(new MethodInvoker(delegate(){ label1.Text = "This will work"; })); } 

http://jaysonknight.com/blog/archive/2007/02/14/using-anonymous-methods-for-control-invoke-control-begininvoke.aspx

Vous souvenez-vous d’utiliser InvokeRequired ? Cela vous permettra de mettre à jour un élément de l’interface utilisateur sur le thread d’interface utilisateur à partir du thread du minuteur.

Je suppose que vous parlez d’une application WinForms.

Lorsque vous essayez de mettre à jour un élément de formulaire (qui réside sur le thread d’interface utilisateur) à partir d’un autre thread, vous devez utiliser Control.Invoke ou Control.BeginInvoke . Vous transmettez un délégué à la méthode que vous souhaitez appeler (ou transmettez une méthode anonyme), puis ce délégué est appelé sur le thread d’interface utilisateur plutôt que sur le thread appelant.

Oui, les événements sont exécutés dans le même thread qui les a déclenchés. Il se trouve que System.Timers.Timer utilise par défaut un thread ThreadPool l’événement Elapsed . Utilisez la propriété SynchronizingObject pour que le gestionnaire d’événements Elapsed soit exécuté sur le thread hébergeant l’object cible.

 public partial class Form1 : Form { System.Timers.Timer T = new System.Timers.Timer(); public Form1() { InitializeComponent(); T.Elapsed += new ElapsedEventHandler(T_Elapsed); T.SynchronizingObject = this; T.Start(); } void T_Elapsed(object sender, ElapsedEventArgs e) { label1.Text = "This will not work"; } } 

Si vous faites cela de manière asynchrone (cela ressemble à vous), assurez-vous de capturer les exceptions dans le gestionnaire d’événements ou le rappel. Si un thread d’arrière-plan lève une exception, l’application se bloquera. C’est la cause la plus courante de ce comportement que j’ai vue.

Je ne suis pas un développeur Winform. Mais j’ai entendu quelque chose concernant la classe Timer que vous utilisez. Je pense que vous voudrez peut-être définir ces propriétés et vérifier.

 T.Interval = 5000; //in Mili Seconds T.Enabled = true;