The simplest approach would be to use a lambda expression which would capture the port you're using. A lambda expression is a way of building a delegate "inline" - and one which is able to use the local variables from the method you declare it in.
For example:
foreach (var port in portNames)
{
// Object initializer to simplify setting properties
SerialPort sp = new SerialPort(port, 19200, Parity.None, 8, StopBits.One)
{
Handshake = Hanshake.None,
ReadTimeout = 500,
WriteTimeout = 500
};
sp.DataReceived += (sender, args) =>
{
Thread.Sleep(500); // Not sure you need this...
string data = sp.ReadLine();
Action action = () => {
MessageBox.Show(data.Trim());
sp.Close();
};
BeginInvoke(action);
};
serialPort.Add(sp);
listPorts.Items.Add(port);
}
A few notes about this:
- Just because some data has been received doesn't mean that a whole line has, so
ReadLine
may still block - If you only need to show a message box, you may not need
Control.BeginInvoke
. (If you need to do more here, you might want to extract most of that code into a separate method which just takes a string, then create an action which would call that method.) - Are you sure you want to close the serial port as soon as the first line has been received?