Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invoking with textbox c#

Part of my program uses an event handler for the receive data of my serial port. The idea is when data is received that the text received is then added to the textbox (rx). I did not used to have this problem but something has changed and I can't figure out what. So now I am re-examining the way this is handled.

During the form load of my winform the last thing I do is

if (!serialPort1.IsOpen)
{
     serialPort1.Open();
     serialPort1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
}

Then I have the event handler

private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
     string indata1 = serialPort1.ReadExisting();
    // rx.Text = " "; accidentally posted this. it was from trial and error.  
     rx.AppendText(Environment.NewLine + indata1);
}

When I run the program it stops at the rx.AppendText(Environment.NewLine + indata1); and gives the error

invalidoperationexception was unhandled: Control "accessed from a thread other than the thread it was created on.

From what I have been able to read suggests that I need to use invoke or BeginInvoke.

I have never had problems appending the text before so now I can't understand why it's a problem. Also from what I have been reading on invoking i just don't understand it.

Can someone help me understand how to use the invoke instance for my situation? or perhaps show me another way of appending the text box?

like image 419
eatumup Avatar asked Dec 27 '22 19:12

eatumup


2 Answers

Usually the exception you're seeing occurs when you run in debug mode, and if you run your application in release mode, you're unlikely to see the exception.

However, it is best to use invoke, as you have read. Something like this:

    private delegate void RefreshTextBox();

    private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) {
        //this event is raised in an event separate from UI thread, 
        //so InvokeRequired must be checked and Invoke called to update UI controls. 
        if (this.InvokeRequired) {
            RefreshTextBox d = new RefreshTextBox(RefreshTextBoxResults);
            Invoke(d);
        } else {
            RefreshTextBoxResults();
        }
    }

    private void RefreshTextBoxResults() {
        string indata1 = serialPort1.ReadExisting();
        rx.Text = " ";
        rx.AppendText(Environment.NewLine + indata1);
    }

The first time you see this invoke stuff, it's nearly impossible to follow, but take a close look and give it some time and it will make sense. Promise. :)

like image 84
hmqcnoesy Avatar answered Dec 29 '22 09:12

hmqcnoesy


Updates in GUI applications should only be done on the GUI thread. Another thread attempting to update GUI components directly will result in either the error you described or in seemingly random behavior.

The role of Invoke & friends is to enable a secondary thread to safely forward GUI updates to the GUI thread, which will then process them from a queue.

In your case (assuming WinForms here):

rx.BeginInvoke(
      (Action)(() =>
      {
          rx.AppendText(Environment.NewLine + indata1);
      }));

BeginInvoke is asynchronous, so the thread calling it will not wait for the actual updates to be processed before moving on, while Invoke is synchronous.

like image 30
Tudor Avatar answered Dec 29 '22 10:12

Tudor