Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on
The data received in your serialPort1_DataReceived
method is coming from another thread context than the UI thread, and that's the reason you see this error.
To remedy this, you will have to use a dispatcher as descibed in the MSDN article:
How to: Make Thread-Safe Calls to Windows Forms Controls
So instead of setting the text property directly in the serialport1_DataReceived
method, use this pattern:
delegate void SetTextCallback(string text);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
So in your case:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
txt += serialPort1.ReadExisting().ToString();
SetText(txt.ToString());
}
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on
As per Prerak K's update comment (since deleted):
I guess I have not presented the question properly.
Situation is this: I want to load data into a global variable based on the value of a control. I don't want to change the value of a control from the child thread. I'm not going to do it ever from a child thread.
So only accessing the value so that corresponding data can be fetched from the database.
The solution you want then should look like:
UserContrl1_LOadDataMethod()
{
string name = "";
if(textbox1.InvokeRequired)
{
textbox1.Invoke(new MethodInvoker(delegate { name = textbox1.text; }));
}
if(name == "MyName")
{
// do whatever
}
}
Do your serious processing in the separate thread before you attempt to switch back to the control's thread. For example:
UserContrl1_LOadDataMethod()
{
if(textbox1.text=="MyName") //<<======Now it wont give exception**
{
//Load data correspondin to "MyName"
//Populate a globale variable List<string> which will be
//bound to grid at some later stage
if(InvokeRequired)
{
// after we've done all the processing,
this.Invoke(new MethodInvoker(delegate {
// load the control with the appropriate data
}));
return;
}
}
}
Thread exception error in C# :Cross-thread operation not valid: Control 'lblp4' accessed from a Cross-thread operation not valid
As the exception suggests, you're accessing controls from a thread other than the one that that created the control (specifically, your ph1..5 threads all attempt to access the UI).
To correct this, you need to use the Invoke()
method on the controls so that the accesses are performed on the main UI thread.
Perhaps add a function to Philosopher
as follows:
private void UpdateText(Label label, string text)
{
// If the current thread is not the UI thread, InvokeRequired will be true
if (label.InvokeRequired)
{
// If so, call Invoke, passing it a lambda expression which calls
// UpdateText with the same label and text, but on the UI thread instead.
label.Invoke((Action)(() => UpdateText(label, text)));
return;
}
// If we're running on the UI thread, we'll get here, and can safely update
// the label's text.
label.Text = text;
}
Then, whenever you have something like:
AZsys.Program.frm.lblp1.Text = "Eating...";
Replace it with:
UpdateText(AZsys.Program.frm.lblp1, "Eating...");
Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on
The data received in your serialPort1_DataReceived
method is coming from another thread context than the UI thread, and that's the reason you see this error.
To remedy this, you will have to use a dispatcher as descibed in the MSDN article:
How to: Make Thread-Safe Calls to Windows Forms Controls
So instead of setting the text property directly in the serialport1_DataReceived
method, use this pattern:
delegate void SetTextCallback(string text);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
So in your case:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
txt += serialPort1.ReadExisting().ToString();
SetText(txt.ToString());
}
Cross-thread operation not valid: Control 'RichTextBox' accessed from a thread other than the thread it was created on
You can't access UI elements from just any thread - it must be on the UI thread. With a handler like that, you can't assume you are on the UI thread and actually you should assume you may not be. The way you ensure a UI control is accessed properly, always check if InvokeRequired
before accessing it.
Dim text As String
If control.InvokeRequired Then
control.Invoke(Sub() text = control.Text)
Else
text = control.Text
End If
In your case, the issue is in HandleUpdateAsync
. The line of code
Await botClient.SendTextMessageAsync("chatid", RichTextBox1.Text)
could be changed to
Dim text As String
If RichTextBox1.InvokeRequired Then
RichTextBox1.Invoke(Sub() text = RichTextBox1.Text)
Else
text = RichTextBox1.Text
End If
Await botClient.SendTextMessageAsync("chatid", text)
The accepted way to do this is not inline in the code like that. Your google search has found it. Generally, it's like this
Private Function GetRichTextBox1Text() As String
If RichTextBox1.InvokeRequired Then
Return RichTextBox1.Invoke(AddressOf GetRichTextBox1Text)
Else
Return RichTextBox1.Text
End If
End Function
Await botClient.SendTextMessageAsync("chatid", GetRichTextBox1Text())
Nobody wants to do this all the time. You can write extension methods (for action and simple function) in a Module like this, and of course you can extrapolate on these for any number of arguments
<Extension(), DebuggerHidden()>
Public Sub InvokeIfRequired(control As Control, action As MethodInvoker)
If control.InvokeRequired Then control.Invoke(action) Else action()
End Sub
' No parameters
<Extension(), DebuggerHidden()>
Public Function InvokeIfRequired(Of TR)(control As Control, func As Func(Of TR)) As TR
If control.InvokeRequired Then
Return control.Invoke(func)
Else
Return func.Invoke()
End If
End Function
' One parameter
<Extension(), DebuggerHidden()>
Public Function InvokeIfRequired(Of T1, TR)(control As Control, func As Func(Of T1, TR), arg1 As T1) As TR
If control.InvokeRequired Then
Return CType(control.Invoke(func, arg1), TR)
Else
Return func.Invoke(arg1)
End If
End Function
' n parameters can be extrapolated...
In your case, use the function
Await botClient.SendTextMessageAsync("chatid", RichTextBox1.InvokeIfRequired(Function() RichTextBox1.Text))
Related Topics
How to Convert a Byte Array to a Hexadecimal String, and Vice Versa
C# Interfaces. Implicit Implementation Versus Explicit Implementation
How to Recursively List All the Files in a Directory in C#
Listing All Permutations of a String/Integer
Using Xpath With Default Namespace in C#
How to Get the Index of the Current Iteration of a Foreach Loop
Pass an Instantiated System.Type as a Type Parameter For a Generic Class
Validate a Username and Password Against Active Directory
Why Did I Get the Compile Error "Use of Unassigned Local Variable"
String.Replace (Or Other String Modification) Not Working
In C#, Why Can't a List≪String≫ Object Be Stored in a List≪Object≫ Variable