Search code examples
c#multithreadinginvokeuart

Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on


I want to send temperature value from a microcontroller using UART to C# interface and Display temperature on Label.Content. Here is my microcontroller code:

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

and my C# code is:

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

but exception arises there "Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on" Please tell me how to get temperature string from my microcontroller and remove this Error!


Solution

  • The data received in your serialPort1_DataReceived method is coming from another thread context than the UI thread, and that's the reason you see this error.
    To remedy this, you will have to use a dispatcher as descibed in the MSDN article:
    How to: Make Thread-Safe Calls to Windows Forms Controls

    So instead of setting the text property directly in the serialport1_DataReceived method, use this pattern:

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

    So in your case:

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