Opération croisée non valide: contrôle ‘textBox1’ accessible depuis un thread autre que celui sur lequel il a été créé

Je veux envoyer la valeur de la température d’un microcontrôleur en utilisant UART à l’interface C # et afficher la température sur Label.Content . Voici mon code microcontrôleur:

 while(1) { key_scan(); // get value of temp if (Usart_Data_Ready()) { while(temperature[i]!=0) { if(temperature[i]!=' ') { Usart_Write(temperature[i]); Delay_ms(1000); } i = i + 1; } i =0; Delay_ms(2000); } } 

et mon code C # est:

 private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { txt += serialPort1.ReadExisting().ToSsortingng(); textBox1.Text = txt.ToSsortingng(); } 

mais une exception survient là “L’ opération inter-thread n’est pas valide: contrôlez ‘textBox1’ à partir d’un thread autre que celui sur lequel il a été créé ” S’il vous plaît dites-moi comment récupérer la chaîne de température de mon microcontrôleur et supprimer cette erreur!

Les données reçues dans votre méthode serialPort1_DataReceived proviennent d’un autre contexte de thread que le thread d’interface utilisateur, et c’est la raison pour laquelle vous voyez cette erreur.
Pour remédier à cela, vous devrez utiliser un répartiteur tel que décrit dans l’article MSDN:
Comment: effectuer des appels thread-safe avec des contrôles Windows Forms

Ainsi, au lieu de définir la propriété text directement dans la méthode serialport1_DataReceived , utilisez ce modèle:

 delegate void SetTextCallback(ssortingng text); private void SetText(ssortingng text) { // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. if (this.textBox1.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); } else { this.textBox1.Text = text; } } 

Donc dans votre cas:

 private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { txt += serialPort1.ReadExisting().ToSsortingng(); SetText(txt.ToSsortingng()); } 

Je ne sais pas si c’est assez bon, mais j’ai créé une classe ThreadHelperClass statique et l’ai implémentée comme suit. Maintenant, je peux facilement définir la propriété text de divers contrôles sans trop de codage.

 public static class ThreadHelperClass { delegate void SetTextCallback(Form f, Control ctrl, ssortingng text); ///  /// Set text property of various controls ///  /// The calling form ///  ///  public static void SetText(Form form, Control ctrl, ssortingng text) { // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. if (ctrl.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); form.Invoke(d, new object[] { form, ctrl, text }); } else { ctrl.Text = text; } } } 

En utilisant le code:

  private void btnTestThread_Click(object sender, EventArgs e) { Thread demoThread = new Thread(new ThreadStart(this.ThreadProcSafe)); demoThread.Start(); } // This method is executed on the worker thread and makes // a thread-safe call on the TextBox control. private void ThreadProcSafe() { ThreadHelperClass.SetText(this, textBox1, "This text was set safely."); ThreadHelperClass.SetText(this, textBox2, "another text was set safely."); } 

vous pouvez simplement le faire.

 TextBox.CheckForIllegalCrossThreadCalls = false; 

Utilisez les extensions suivantes et passez simplement l’action comme suit:

 _frmx.PerformSafely(() => _frmx.Show()); _frmx.PerformSafely(() => _frmx.Location = new Point(x,y)); 

Classe d’extension:

 public static class CrossThreadExtensions { public static void PerformSafely(this Control target, Action action) { if (target.InvokeRequired) { target.Invoke(action); } else { action(); } } public static void PerformSafely(this Control target, Action action,T1 parameter) { if (target.InvokeRequired) { target.Invoke(action, parameter); } else { action(parameter); } } public static void PerformSafely(this Control target, Action action, T1 p1,T2 p2) { if (target.InvokeRequired) { target.Invoke(action, p1,p2); } else { action(p1,p2); } } } 

Dans le même ordre d’idées que les réponses précédentes, mais un ajout très court qui permet d’utiliser toutes les propriétés de contrôle sans avoir d’exception d’invocation de threads.

Méthode d’assistance

  ///  /// Helper method to determin if invoke required, if so will rerun method on correct thread. /// if not do nothing. ///  /// Control that might require invoking /// action to preform on control thread if so. /// true if invoke required public bool ControlInvokeRequired(Control c,Action a) { if (c.InvokeRequired) c.Invoke(new MethodInvoker(delegate { a(); })); else return false; return true; } 

Utilisation de l’échantillon

  // usage on textbox public void UpdateTextBox1(Ssortingng text) { //Check if invoke requied if so return - as i will be recalled in correct thread if (ControlInvokeRequired(textBox1, () => UpdateTextBox1(text))) return; textBox1.Text = ellapsed; } //Or any control public void UpdateControl(Color c,Ssortingng s) { //Check if invoke requied if so return - as i will be recalled in correct thread if (ControlInvokeRequired(myControl, () => UpdateControl(c,s))) return; myControl.Text = s; myControl.BackColor = c; } 

Utilisez un conteneur partagé pour transférer des données entre les threads.