PC Review


Reply
Thread Tools Rate Thread

Cross Thread Exception after reading Asynchronous Serial Port

 
 
Mo
Guest
Posts: n/a
 
      12th Nov 2006
I am trying to set a text box value when data is received from the com
port (barcode reader). I am getting the following error when I try to
set the text box TXNumber after data is received

Cross-thread operation not valid: Control 'TXNumber' accessed from a
thread other than the thread it was created on.

Any ideas how to work around this problem?

Thanks
Here is my code
________ Initialize Scanner _______________
public void Initialize_Scanner()
{
sp.BaudRate = 9600;
sp.Parity = Parity.None;
sp.DataBits = 8;
sp.StopBits = StopBits.One;
sp.ReadTimeout = 1500;
sp.DataReceived += new
SerialDataReceivedEventHandler(sp_DataReceived);
sp.Open();

}
________ Data Received? ______________
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{

string ret = "\r";
string tempstring = sp.ReadLine().Replace(ret, "");
sp.Close();
this.TXNumber.Text = tempstring;

if (tempstring.Length> 0)
{
Run_process();
sp.Open();
}


}

 
Reply With Quote
 
 
 
 
=?Utf-8?B?TWFyayBSLiBEYXdzb24=?=
Guest
Posts: n/a
 
      12th Nov 2006
Hi Mo,
you can only modify a control from the thread on which it was created. So
in your event handler sp_DataReceived you need to call the Invoke method on
the textbox passing in a delegate to execute on the thread that created the
control i.e.

public void Initialize_Scanner()
{
sp.BaudRate = 9600;
sp.Parity = Parity.None;
sp.DataBits = 8;
sp.StopBits = StopBits.One;
sp.ReadTimeout = 1500;
sp.DataReceived += new
SerialDataReceivedEventHandler(sp_DataReceived);
sp.Open();

}

void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{

string ret = "\r";
string tempstring = sp.ReadLine().Replace(ret, "");
sp.Close();

//Will update the text box.
this.TXNumber.Invoke(new SetTextValueHander(SetTextValue)));

if (tempstring.Length> 0)
{
Run_process();
sp.Open();
}
}

delegate void SetTextValueHandler(string value);

void SetTextValue(string value)
{
this.TXNumber.Text = value;
}

The Invoke is syncronous, if you want to update the GUI asyncronously then
you can call BeginInvoke.

Mark.
--
http://www.markdawson.org


"Mo" wrote:

> I am trying to set a text box value when data is received from the com
> port (barcode reader). I am getting the following error when I try to
> set the text box TXNumber after data is received
>
> Cross-thread operation not valid: Control 'TXNumber' accessed from a
> thread other than the thread it was created on.
>
> Any ideas how to work around this problem?
>
> Thanks
> Here is my code
> ________ Initialize Scanner _______________
> public void Initialize_Scanner()
> {
> sp.BaudRate = 9600;
> sp.Parity = Parity.None;
> sp.DataBits = 8;
> sp.StopBits = StopBits.One;
> sp.ReadTimeout = 1500;
> sp.DataReceived += new
> SerialDataReceivedEventHandler(sp_DataReceived);
> sp.Open();
>
> }
> ________ Data Received? ______________
> void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
> {
>
> string ret = "\r";
> string tempstring = sp.ReadLine().Replace(ret, "");
> sp.Close();
> this.TXNumber.Text = tempstring;
>
> if (tempstring.Length> 0)
> {
> Run_process();
> sp.Open();
> }
>
>
> }
>
>

 
Reply With Quote
 
Mo
Guest
Posts: n/a
 
      12th Nov 2006
Thank you for the response. This process is still a mystery to me. I am
getting Mthod name expected in the line

this.TXNumber.Invoke(new SetTextValueHander(SetTextValue(tempstring)));

Any Ideas?

The code to look like:

delegate void SetTextValueHandler(string value);
void SetTextValue(string value)
{
this.TXNumber.Text = value;
}

void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string ret = "\r";
string tempstring = sp.ReadLine().Replace(ret, "");
sp.Close();

this.TXNumber.Invoke(new
SetTextValueHander(SetTextValue(tempstring)));


if (tempstring.Length> 0)
{
Run_process();
sp.Open();
}

}

 
Reply With Quote
 
=?Utf-8?B?TWFyayBSLiBEYXdzb24=?=
Guest
Posts: n/a
 
      12th Nov 2006
Hi Mo,
sorry, the sample code I sent previously was not complete - note to self
"don't post when very late :-)" when you call Invoke if you pass parameters
to your delegate then you also need to specify those in the call to invoke,
as values of an object array, so:

> this.TXNumber.Invoke(new
> SetTextValueHander(SetTextValue(tempstring)));


would be:

this.TXNumber.Invoke(new SetTextValueHandler(SetTextValue(tempString)), new
object[]{tempString});

The idea behind calling invoke is that you can only modify a control on the
same thread that created the control. The sp_DataReceived function is called
in the context of a different thread, one that is used to receive the data
from your serial port, so calling invoke will swap control back to the thread
that created the textbox (Since you are calling Invoke from the textbox
object). The delegate is like a strongly typed function pointer, the
delegate defines the method signature that it can point to, in our case a
method which has a return of void and takes a string parameter, so saying:

new SetTextValueHandler(SetTextValue)

is creating a function pointer in effect to the SetTextValue that the
textbox control should call once it gets control.

In your case you are processing data so either you need to make sure the
call to the method you call is fast or you can use the BeginInvoke which is
asyncronous and does not wait for the method pointed to by the delegate to
complete.

Hope that helps.

Thanks
Mark.
--
http://www.markdawson.org


"Mo" wrote:

> Thank you for the response. This process is still a mystery to me. I am
> getting Mthod name expected in the line
>
> this.TXNumber.Invoke(new SetTextValueHander(SetTextValue(tempstring)));
>
> Any Ideas?
>
> The code to look like:
>
> delegate void SetTextValueHandler(string value);
> void SetTextValue(string value)
> {
> this.TXNumber.Text = value;
> }
>
> void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
> {
> string ret = "\r";
> string tempstring = sp.ReadLine().Replace(ret, "");
> sp.Close();
>
> this.TXNumber.Invoke(new
> SetTextValueHander(SetTextValue(tempstring)));
>
>
> if (tempstring.Length> 0)
> {
> Run_process();
> sp.Open();
> }
>
> }
>
>

 
Reply With Quote
 
Mo
Guest
Posts: n/a
 
      12th Nov 2006
Thank you Mark, Great post. had to change the synatx to

this.TXNumber.Invoke(new SetTextValueHandler(SetTextValue), new
object[] { tempstring });

And it works like a charm which brings me to the nex problem along the
same line. I am trying to execute a method which is calling a couple of
other methods

public void Run_process()
{
Generate_Label(TXNumber.Text);
Get_P1(TXNumber.Text);
Process_P1(TXNumber.Text);
}
public void Generate_Label(string TXNumber)
{
//do something
}
etc...

and I am gettiing the same error wen I call these methods "//do
Something" . How do I go about invoking these methods in my main form?

Thank you for all your help.
Mo

 
Reply With Quote
 
=?Utf-8?B?TWFyayBSLiBEYXdzb24=?=
Guest
Posts: n/a
 
      12th Nov 2006
Hi Mo,
in general you can do something like the following pattern when calling a
method and you think it could be called outside of the context of the main UI
thread, assuming in the case below that "this" refers to the form class
instance:

delegate void TextParameterHandler(string value);

void SetMyText(string value)
{
//Check to see if invoke is required to change context
//to the main UI thread.
if(this.InvokeRequired)
{
//Call the same method in the context of the main UI thread.
this.Invoke(new TextParameterHandler(SetMyText), new object[]{value});
}
else
{
//calling thread is same as the one that created
//the controls, we can update safely.

myTextBox.Text = value;
myLabel.Text = value;
}
}


See http://msdn2.microsoft.com/en-us/library/zyzhdc6b.aspx for more info and
also John Skeet has a good article on this:
http://www.yoda.arachsys.com/csharp/...winforms.shtml

Hope that helps.
Mark.
--
http://www.markdawson.org


"Mo" wrote:

> Thank you Mark, Great post. had to change the synatx to
>
> this.TXNumber.Invoke(new SetTextValueHandler(SetTextValue), new
> object[] { tempstring });
>
> And it works like a charm which brings me to the nex problem along the
> same line. I am trying to execute a method which is calling a couple of
> other methods
>
> public void Run_process()
> {
> Generate_Label(TXNumber.Text);
> Get_P1(TXNumber.Text);
> Process_P1(TXNumber.Text);
> }
> public void Generate_Label(string TXNumber)
> {
> //do something
> }
> etc...
>
> and I am gettiing the same error wen I call these methods "//do
> Something" . How do I go about invoking these methods in my main form?
>
> Thank you for all your help.
> Mo
>
>

 
Reply With Quote
 
 
 
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Serial Port thread Denis R Charron Microsoft Dot NET Compact Framework 3 16th Sep 2009 08:19 PM
Cross-Thread Exception Relaxin Microsoft Dot NET 8 22nd Mar 2008 09:21 AM
BackgroundWorker and ListView cross-thread exception Jazza Microsoft Dot NET Framework Forms 1 16th Feb 2008 01:42 PM
'cross-thread operation not valid' exception / multithreaded compo =?Utf-8?B?SGFpcmxpcERvZzU4?= Microsoft Dot NET 11 24th Apr 2006 03:28 AM
Asynchronous Serial port shayke via DotNetMonster.com Microsoft C# .NET 2 30th Nov 2005 05:01 PM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 09:04 PM.