I have a problem similar to the topic "Display serial in to textbox - Cross thread operation" but I don't understand the answers given for that.
I created a very simple C# form to send/receive serial data, based on a tutorial video example I found. Works great, but the example requires you to click a button to receive data, whereas I want to have it now automatically display whatever is received by updating the "Received" textbox.
Program.cs is generated by VSE2015:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace spcontrol
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
Form1.cs shows working code based on the tutorial example (i.e. "Receive" button must be clicked):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
namespace spcontrol
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
GetAvailablePorts();
//serialPort1.DataReceived += new SerialDataReceivedEventHandler(port_OnReceiveData);
}
void GetAvailablePorts()
{
string[] ports = SerialPort.GetPortNames();
comboBox_portnames.Items.AddRange(ports);
}
private void button_openport_Click(object sender, EventArgs e)
{
try
{
if (comboBox_portnames.Text == "" || comboBox_baudrate.Text == "")
{
textBox_received.Text = "Please select port settings.";
}
else
{
textBox_received.Text = "";
serialPort1.PortName = comboBox_portnames.Text;
serialPort1.BaudRate = Convert.ToInt32(comboBox_baudrate.Text);
serialPort1.Open();
button_send.Enabled = true;
button_receive.Enabled = true;
textBox_sent.Enabled = true;
button_openport.Enabled = false;
button_closeport.Enabled = true;
comboBox_portnames.Enabled = false;
comboBox_baudrate.Enabled = false;
serialPort1.DataBits = 8;
serialPort1.Parity = Parity.None;
serialPort1.StopBits = StopBits.One;
serialPort1.Handshake = Handshake.None;
label_config.Text = serialPort1.PortName + " " + serialPort1.BaudRate + " 8N1 None";
progressBar_status.Value = progressBar_status.Maximum;
}
}
catch (UnauthorizedAccessException)
{
textBox_received.Text = "Unauthorized access.";
}
}
private void button_closeport_Click(object sender, EventArgs e)
{
serialPort1.Close();
button_send.Enabled = false;
button_receive.Enabled = false;
textBox_sent.Enabled = false;
button_openport.Enabled = true;
button_closeport.Enabled = false;
comboBox_portnames.Enabled = true;
comboBox_baudrate.Enabled = true;
progressBar_status.Value = progressBar_status.Minimum;
}
private void button_send_Click(object sender, EventArgs e)
{
serialPort1.WriteLine(textBox_sent.Text);
textBox_sent.Text = "";
textBox_sent.Focus();
}
private void button_receive_Click(object sender, EventArgs e)
{
try
{
textBox_received.Text = serialPort1.ReadLine();
}
catch (TimeoutException)
{
textBox_received.Text = "Timeout exception.";
}
}
//private void port_OnReceiveData(object sender, SerialDataReceivedEventArgs e)
//{
// SerialPort sp = (SerialPort)sender;
// textBox_received.Text += sp.ReadExisting();
//}
}
}
The commented-out code is my attempt at automating the received data textbox display (uncomment this code and comment out the "try" statement within "button_receive_Click" function.)
But doing so gives me the cross-thread error:
Exception thrown: 'System.InvalidOperationException' in System.Windows.Forms.dll An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll Additional information: Cross-thread operation not valid: Control 'textBox_received' accessed from a thread other than the thread it was created on.
I've read things about using Invoke or BeginInvoke but there's never enough context in the answers for me (a non-programmer) to figure out how to implement, plus usually the answers are all over the map and there's no consensus for which is correct/best. Can someone please provide a simple solution for what I need to add to my code to make this work? Thanks.