跨线程操作无效:从其创build线程以外的线程访问的“textBox1”控件

我想从一个微控制器使用UART发送温度值到C#接口并在Label.Content上显示温度。 这是我的微控制器代码:

  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); } } 

和我的C#代码是:

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

但在那里出现exception“ 跨线程操作无效:控制'textBox1'访问从一个线程以外的线程它创build ”请告诉我如何从我的微控制器温度string,并删除此错误!

您的serialPort1_DataReceived方法中收到的数据来自另一个线程上下文,而不是UI线程,这就是您看到这个错误的原因。
为了解决这个问题,你将不得不使用MSDN文章中描述的调度器:
如何:进行线程安全调用Windows窗体控件

因此,不要直接在serialport1_DataReceived方法中设置text属性, serialport1_DataReceived使用以下模式:

 delegate void SetTextCallback(string text); private void SetText(string 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; } } 

所以在你的情况下:

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

我不知道这是否足够好,但我做了一个静态的ThreadHelperClass类,并实现它如下。现在我可以很容易地设置各种控件的文本属性,没有太多的编码。

 public static class ThreadHelperClass { delegate void SetTextCallback(Form f, Control ctrl, string text); /// <summary> /// Set text property of various controls /// </summary> /// <param name="form">The calling form</param> /// <param name="ctrl"></param> /// <param name="text"></param> public static void SetText(Form form, Control ctrl, string 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; } } } 

使用代码:

  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."); } 

你可以简单地做到这一点。

 TextBox.CheckForIllegalCrossThreadCalls = false; 

使用以下扩展名,只需传递如下操作:

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

扩展类:

 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<T1>(this Control target, Action<T1> action,T1 parameter) { if (target.InvokeRequired) { target.Invoke(action, parameter); } else { action(parameter); } } public static void PerformSafely<T1,T2>(this Control target, Action<T1,T2> action, T1 p1,T2 p2) { if (target.InvokeRequired) { target.Invoke(action, p1,p2); } else { action(p1,p2); } } } 

沿着以前的答案相同的路线,但一个非常短的添加,允许使用所有控制属性没有跨线程invokationexception。

帮助者方法

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

样例用法

  // usage on textbox public void UpdateTextBox1(String 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,String 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; } 

使用共享容器在线程之间传输数据。