PongPagong
PongPagong

Reputation: 47

Serial Port on Winforms

I was wondering why my serial port is not recieving when i am using the winform application, but on the console application i used the same code it's working fine.

Note: I did put a breakpoint on the dataReceive event but it's not receiving any events. It's receiving only once , when the screen is loaded,but after that never recieve an events

delegate void SetTextCallback(string text);

SerialPort serRec = null;

SerialPort ser = null;

private void SetText(string text)
    {
        if (this.textBox1.InvokeRequired)
        {
            SetTextCallback d = new SetTextCallback(SetText);
            this.BeginInvoke(d, new object[] { text });
        }
        else
        {
            this.textBox1.Text = text;
        }
    }

private void button1_Click(object sender, EventArgs e)
    {
        serRec = new SerialPort("COM5", 9600, Parity.None, 8, StopBits.One);
        serRec.Open();

        serRec.DataReceived += (sendexr, se) =>
        {
            var r = serRec.ReadLine();
            SetText(r);
        };
        serRec.ReadTimeout = 1000;

        ser = new SerialPort("COM6", 9600, Parity.None, 8, StopBits.One);
        ser.Open();
        while (true)
        {
            ser.WriteTimeout = 1000;
            ser.WriteLine(Guid.NewGuid().ToString());

            System.Threading.Thread.Sleep(3000);
        }
    }

Upvotes: 3

Views: 2884

Answers (1)

TheGeneral
TheGeneral

Reputation: 81493

This is just a guess, however my spidey senses tells me its most likely a UI threading issue,

The SerialPort.DataReceived event is raised on a separate thread. If you need to asynchronously handle the receipt of data and update the UI you will need to marshal back to the UI thread.

From MSDN

The DataReceived event is raised on a secondary thread when data is received from the SerialPort object. Because this event is raised on a secondary thread, and not the main thread, attempting to modify some elements in the main thread, such as UI elements, could raise a threading exception. If it is necessary to modify elements in the main Form or Control, post change requests back using Invoke...

Exmaple

private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) {
    var port = (SerialPort)sender;
    string data = port.ReadExisting();

    UpdateGui(data);
}

private void UpdateGui(string data) {
    if (this.InvokeRequired) {
        this.Invoke(new Action( d => UpdateGui(d) ));
        return;
    }

    this.txtBox1.Text = data;
}

Note : The reason this probably didn't make a difference in a console app is because you can write to the console on any thread.


Control.InvokeRequired Property

Gets a value indicating whether the caller must call an invoke method when making method calls to the control because the caller is on a different thread than the one the control was created on.

Control.Invoke Method (Delegate)

Executes the specified delegate on the thread that owns the control's underlying window handle.


Update

Comment from MickyD

Best to use BeginInvoke rather than Invoke, latter can lead to deadlocks

Control.BeginInvoke Method (Delegate)

Executes the specified delegate asynchronously on the thread that the control's underlying handle was created on.

Upvotes: 3

Related Questions