1

I am trying to use the DataReceived event but my method OnDataReceived() is not able to be called from the method Main(). I've proven this by adding the line System.Windows.Forms.Application.Exit(); which would effectively close the windows form application; but it does not.

Basically I just want to run the method OnDataReceived upon receiving data through my serial port. I was hoping to do this with arduino.DataReceived += OnDataReceived; but it was proven unsuccessful. Feel free to view my comments for guidance. Also I have introduced the string received and serial port arduino outside of any method, would this affect the functionality?

public partial class Form1 : Form
{

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {

    }

    string received;
    private SerialPort arduino;

    private void button2_Click(object sender, EventArgs e)
    {
        comboBox1.Items.Clear();
        string[] ports = SerialPort.GetPortNames();
        foreach (string port in ports)
        {
            comboBox1.Items.Add(port);
        }
        comboBox1.SelectedIndex = 0;
    }

    private void Main(string port)
    {
        using (arduino = new SerialPort(port))
        {
            arduino.Open();
            arduino.DtrEnable = true;
            arduino.RtsEnable = true;
            arduino.BaudRate = 9600;

            arduino.DataReceived += OnDataReceived; //when data is received, call method below.

            //System.Windows.Forms.Application.Exit(); //this works, which means the above line has been run too.
        }
    }

    private void OnDataReceived(object sender, SerialDataReceivedEventArgs e) //this method does not get called from the above method.
    {
        System.Windows.Forms.Application.Exit();
        received = arduino.ReadLine();
    }

    public void checkBox1_CheckedChanged(object sender, EventArgs e)
    {
        Main(comboBox1.Text);
        if (checkBox1.Checked)
        {
            checkBox1.Text = "Listening...";
                if (received == "S\r")
                {
                    arduino.Close();
                    //System.Diagnostics.Process.Start("shutdown", "/f /r /t 0");
                    //System.Windows.Forms.Application.Exit();
                }
        }
        else
        {
            checkBox1.Text = "Start";
        }

        }
    }
}
  • *But it was proven unsuccessful.* How? What was the error? What code did you try to execute in `OnDataReceived`? – Reza Aghaei Aug 22 '16 at 12:38
  • The [`DataReceived`](https://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived(v=vs.110).aspx#Anchor_1) 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`, which will do the work on the proper thread. – Reza Aghaei Aug 22 '16 at 12:41
  • Also for debugging your application you can simply use [Break Point](https://msdn.microsoft.com/en-us/library/5557y8b4.aspx). Also you can use `Console.WriteLine` to write something in [Output Window](https://msdn.microsoft.com/en-us/library/3hk6fby3.aspx). Also you can use traditional `MessageBox.Show` method. – Reza Aghaei Aug 22 '16 at 12:46
  • By _unsuccessful_ I meant that the method was not called at all, I was hoping to call it it using `arduino.DataReceived += OnDataReceived;`. I don't understand what you mean by _post change requests back using `Invoke`_. Is `Invoke` my only alternative? I have seen some examples in which they were able to successfully use the DataRecieved() event. I know that SO is not a "write my code" website, but if you are willing, I would appreciate a reference to some code involving `Invoke`. – Alexander Stroborg Aug 22 '16 at 12:51
  • Also read @MongZhu 's answer. – Reza Aghaei Aug 22 '16 at 12:53
  • For invoke sample, take a look at this post.[Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on](http://stackoverflow.com/questions/142003/cross-thread-operation-not-valid-control-accessed-from-a-thread-other-than-the). But make sure you fixed the problem which mentioned by MongZhu . – Reza Aghaei Aug 22 '16 at 12:56

1 Answers1

1

One of your problems is the using block:

using (arduino = new SerialPort(port))
{
    arduino.Open();
    arduino.DtrEnable = true;
    arduino.RtsEnable = true;
    arduino.BaudRate = 9600;

    arduino.DataReceived += OnDataReceived; //when data is received, call method below.

    //System.Windows.Forms.Application.Exit(); //this works, which means the above line has been run too.
}

When the code is executed arduino.Dispose is called and your SerialPort vanishes into oblivion and so does the event registration. Therefore you event is never fired.

To Check whether your event works. Use a breakpoint in the Debugger.

EDIT:

The null value means that it has been unregistered. Since the SerialPort has been disposed.

Basically I just want to run the method OnDataReceived upon receiving data through my serial port.

The thing is that you don't run this method. It is designed (like any other event) to be fired when needed. So it will help you to remain passive and your GUI can remain responsive (since you don't have to run it actively).

A SerialPort can be written to and read from when it is open. So if you want to monitor it, just open it up, register to the event and wait to see what happens.

public void checkBox1_CheckedChanged(object sender, EventArgs e)
{

    if (checkBox1.Checked)
    {

        arduino = new SerialPort(port);

        // you should specify these before opening the port
        arduino.DtrEnable = true;
        arduino.RtsEnable = true;
        arduino.BaudRate = 9600;

        // register to the event
        arduino.DataReceived += OnDataReceived;
        //open the port
        arduino.Open();

        // tell the user
        checkBox1.Text = "Listening...";
    }                
}

In the Event you should specify what you want to do when the data arrives:

private void OnDataReceived(object sender, SerialDataReceivedEventArgs e) //this method does not get called from the above method.
{
    // first of all read out what you have received!
    received = arduino.ReadLine();
    // do something with the information

    // if you have a condition and really want to close the application or shut down the computer
   // first close the port!!!
   arduino.Close();

}

Your old version:

    System.Windows.Forms.Application.Exit();
    received = arduino.ReadLine();

will probably not work. It is like closing the door behind you and then trying to pick up the phone that is still in your closed flat...

Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
  • When placing a breakpoint on the line `arduino.DataReceived += OnDataReceived;` the value for `arduino.DataReceived` is "null"[Screenshot, view the "autos" tab at the bottom](http://puu.sh/qKeH7/1a231d1b6b.png) Does this mean that my SerialPort has vanished into oblivion? – Alexander Stroborg Aug 22 '16 at 13:04
  • My reason for using `using` is because outside of the method, any calls made towards the serial port result in a "access denies to the COM port". Would you know of any solution to this problem? – Alexander Stroborg Aug 22 '16 at 13:05
  • @AlexanderStroborg I edited my Answer. Hope it helps. If not give me a comment – Mong Zhu Aug 22 '16 at 17:06
  • @AlexanderStroborg as already mentioned in the answer. The port has to be open to gain access. – Mong Zhu Aug 22 '16 at 17:53