Introduction
As RS-232 is still used often in industrial applications, Microsoft has added the SerialPort class to its .NET 2.0 framework.
When communicating with a Windows Forms application and displaying the received data, for instance in a TextBox, the problem occurs, that the serial port and the textbox are using different threads. MSDN describes a way to solve this problem.
As an example of how to apply all this, using Visual C#, a small application has been built:

First of all, you have to place, from the Toolbox=>Components, a SerialPort onto the Form.
Then, in the Properties, set the serial port to 9600,8N1 and the port name to X (don't be alarmed; after the application has started, you will get the opportunity to choose a proper COM-name!)
Now, place the top-textbox (txtIn), showing received data, and the lower textbox (txtOut), showing the data to be send after clicking the Send button. Optionally, you could also place a SttusStrip (as I did).
Add a ComboBox (cmbComSelect) with DropDownStyle set to DropDown and Sorted set to true.
The Namespace
The System.IO.Ports namespace contains classes for controlling serial ports. The most important class is the SerialPort class.
The Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
namespace RS232
{
public partial class fclsRS232Tester : Form
{
string InputData = String.Empty;
delegate void SetTextCallback(string text);
public fclsRS232Tester()
{
InitializeComponent();
string[] ports = SerialPort.GetPortNames();
foreach (string port in ports)
{
cmbComSelect.Items.Add(port);
}
}
private void cmbComSelect_SelectionChangeCommitted(object sender,
EventArgs e)
{
if (port.IsOpen) port.Close();
port.PortName = cmbComSelect.SelectedItem.ToString();
stsStatus.Text = port.PortName + ": 9600,8N1";
try
{
port.Open();
}
catch
{
MessageBox.Show("Serial port " + port.PortName +
" cannot be opened!", "RS232 tester",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
cmbComSelect.SelectedText = "";
stsStatus.Text = "Select serial port!";
}
}
private void btnSend_Click(object sender, EventArgs e)
{
if (port.IsOpen) port.WriteLine(txtOut.Text);
else MessageBox.Show("Serial port is closed!",
"RS232 tester",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
txtOut.Clear();
}
private void btnClear_Click(object sender, EventArgs e)
{
txtIn.Clear();
}
private void port_DataReceived_1(object sender,
SerialDataReceivedEventArgs e)
{
InputData = port.ReadExisting();
if (InputData != String.Empty)
{
SetText(InputData);
}
}
private void SetText(string text)
{
if (this.txtIn.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else this.txtIn.Text += text;
}
}
}
Getting the COM-port
The SerialPort gives us a nice method to find all COM-ports available in the computer:
string[] ports = SerialPort.GetPortNames();
Now that we have all ports available, we fill the Items list of the ComboBox:
foreach (string port in ports)
{
cmbComSelect.Items.Add(port);
}
and, through the SelectionChangeCommitted event from the ComboBox, we can choose a particular COM-port.
Because the selected COM-port may be in use, we try to open it, and if an exception is thrown, we catch it and display a proper message.
Achieving thread-safety
The statement txtIn.Text = InputData; will cause problems on receiving data, because the Receive thread is different from the thread which started the textbox!!
To solve this problem in a thread-safe way, we use the following statement instead:
SetText(InputData);
First, we have to declare a delegate method:
delegate void SetTextCallback(string text);
and then this method can be defined as:
private void SetText(string text)
{
if (this.txtIn.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else this.txtIn.Text += text;
}