Hello everyone,
This is my first post after registering today. I've been reading bits and pieces on this site for a while now, and thought I'd take a crack at trying to apply seperating the form logic from the communications logic from a serial communications program called SimpleSerial (http://csharp.simpleserial.com/) using the "Quick and easy custom events" tutorial.
So what I did was create a new class called SerialManager and moved all the comms specific stuff to the new class, then added the events tutorial code to the bottom. I then create an event like so: RaiseFeedback("Opening Com Port"); with Form1 subscribing to this event.
Form1 has:
plus a bit more, that's not relevant to the issue at hand.
SerialManager has the following:
The RaiseFeedback("Opening Com Port"); works fine and I get this on Form1.
The problem comes in the onSerialDataReceived event of the comms port.
I've added a bunch of comments from what I learned in the code below:
So the comms port RX event is running on a different thread. Everything I read so far has the communications code running in the form class and uses this.Invoke(new EventHandler(DisplayText)); or some slight variation to get the text back on the forms thread. But I haven't found anything that makes the whole serial communications code run as a completely seperate class that is instanced from the form.
If I make SerialManager a method that is part of the Form1 class, and do ths same thing SimpleSerial does, I can get it to work, but the whole point of the exercise was to make it a completely seperate class that wasn't tightly coupled to the form.
I don't know if Form1 is running on 1 thread, SerialManager is running on another and the rx event is running on yet another or if both SerialManager and rx event are on the same thread.
In the end, the rx data from the serial port may go to another class that does "stuff" with it and not a form at all, so I really don't want to link the SerialManager class with From1 at the SerialManager level, brcause Form1 will untimately go away.
I tried having the rx event call DisplayText and DisplayText then raise the event back to From1, which just gave me a stack overflow for my trouble. I tried reading a couple of the multi-threading communications tutorial, but they are way over my head.
So now I really don't know where to turn next. There must be a simple way to do this, but I can't figure it out.
Any help would be appreciated.
This is my first post after registering today. I've been reading bits and pieces on this site for a while now, and thought I'd take a crack at trying to apply seperating the form logic from the communications logic from a serial communications program called SimpleSerial (http://csharp.simpleserial.com/) using the "Quick and easy custom events" tutorial.
So what I did was create a new class called SerialManager and moved all the comms specific stuff to the new class, then added the events tutorial code to the bottom. I then create an event like so: RaiseFeedback("Opening Com Port"); with Form1 subscribing to this event.
Form1 has:
public partial class Form1 : Form
{
// Add this variable
SerialManager Arduino;
public Form1()
{
InitializeComponent();
DebugText("Hello");
Arduino = new SerialManager();
Arduino.Feedback += new EventHandler<TextArgs>(Feedback_Received);
Arduino.Open();
}
public void DebugText(string p)
{
textBox1.AppendText(p);
}
void Feedback_Received(object sender, TextArgs e)
{
if (e != null && e.Message != null)
textBox1.AppendText(e.Message);
}
plus a bit more, that's not relevant to the issue at hand.
SerialManager has the following:
public partial class SerialManager
{
private SerialPort serialPort1;
public SerialManager()
{
serialPort1 = new SerialPort();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(onSerialDataReceived);
}
public void Open()
{
RaiseFeedback("Opening Com Port");
serialPort1.PortName = "COM6";
serialPort1.BaudRate = 9600;
The RaiseFeedback("Opening Com Port"); works fine and I get this on Form1.
The problem comes in the onSerialDataReceived event of the comms port.
I've added a bunch of comments from what I learned in the code below:
private string rxString;
private void onSerialDataReceived(object sender, SerialDataReceivedEventArgs e)
{
rxString = serialPort1.ReadExisting();
// serialPort1 runs in it own separate thread behind the scenes.
// This thread cannot directly call any functions in the main thread of our application.
// However, a special function, Invoke( ), will allow it.
// So we use Invoke to call our DisplayText( ) function. RxString is the global string variable accessable by both threads
// Original SimpleSerial way of writing to the textBox1 on Form1.
this.Invoke(new EventHandler(DisplayText));
// this = SerialManager not Form1 in this case and Invoke is not defined
// Only works if:-
// public partial class SerialManager : Form1 & SerialManager is called as a method - not as a constructor of the instance SerialManager
// Adding this causes the following error on Form1:
// Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.
//
RaiseFeedback(rxString);
}
// This works in the context of public partial class SerialManager : Form1, but won't work if this is an instance
// I don't want to do this, I want to use the event (below) as I may not be sending data to a form eventually.
private void DisplayText(object sender, EventArgs e)
{
//textBox1.AppendText(RxString);
}
So the comms port RX event is running on a different thread. Everything I read so far has the communications code running in the form class and uses this.Invoke(new EventHandler(DisplayText)); or some slight variation to get the text back on the forms thread. But I haven't found anything that makes the whole serial communications code run as a completely seperate class that is instanced from the form.
If I make SerialManager a method that is part of the Form1 class, and do ths same thing SimpleSerial does, I can get it to work, but the whole point of the exercise was to make it a completely seperate class that wasn't tightly coupled to the form.
I don't know if Form1 is running on 1 thread, SerialManager is running on another and the rx event is running on yet another or if both SerialManager and rx event are on the same thread.
In the end, the rx data from the serial port may go to another class that does "stuff" with it and not a form at all, so I really don't want to link the SerialManager class with From1 at the SerialManager level, brcause Form1 will untimately go away.
I tried having the rx event call DisplayText and DisplayText then raise the event back to From1, which just gave me a stack overflow for my trouble. I tried reading a couple of the multi-threading communications tutorial, but they are way over my head.
So now I really don't know where to turn next. There must be a simple way to do this, but I can't figure it out.
Any help would be appreciated.