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]
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!
Los datos recibidos en su serialPort1_DataReceived
mé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_DataReceived
mé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());
}
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.");
}