La operación entre subprocesos no es válida: se accede al control 'textBox1' desde un subproceso distinto del subproceso en el que se creó [duplicado]

Resuelto Fatima Zohra asked hace 12 años • 6 respuestas

Quiero enviar el valor de temperatura desde un microcontrolador usando UART a la interfaz C# y mostrar la temperatura encendida Label.Content. Aquí está el código de mi microcontrolador:

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

y mi código C# es:

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

pero surge una excepción allí " La operación entre subprocesos no es válida: se accede al control 'textBox1' desde un subproceso distinto del subproceso en el que se creó " ¡Dígame cómo obtener la cadena de temperatura de mi microcontrolador y eliminar este error!

Fatima Zohra avatar May 27 '12 23:05 Fatima Zohra
Aceptado

Los datos recibidos en su serialPort1_DataReceivedmétodo provienen de otro contexto de subproceso distinto del subproceso de la interfaz de usuario, y esa es la razón por la que ve este error.
Para remediar esto, tendrá que utilizar un despachador como se describe en el artículo de MSDN:
Cómo: realizar llamadas seguras para subprocesos a controles de Windows Forms

Entonces, en lugar de configurar la propiedad de texto directamente en el serialport1_DataReceivedmétodo, use este patrón:

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

Entonces en tu caso:

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
  txt += serialPort1.ReadExisting().ToString();
  SetText(txt.ToString());
}
Magnus Johansson avatar May 27 '2012 16:05 Magnus Johansson

No sé si esto es lo suficientemente bueno, pero creé una clase ThreadHelperClass estática y la implementé de la siguiente manera. Ahora puedo configurar fácilmente las propiedades de texto de varios controles sin mucha codificación.

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

Usando el código:

 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.");
 }
Thunder avatar Apr 05 '2013 10:04 Thunder