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;
}
}
}
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))
Cross-thread operation not valid inside foreach
If going async, then go async all the way. RestSharp allows you to make async calls
So you can refactor data access to
public class GetResults {
public static async Task<List<Result>> GetDataAsync(string url) {
var client = new RestClient();
var request = new RestRequest(url, Method.GET);
request.AddHeader("User-Agent", "Nothing");
IRestResponse<List<Result>> results = await client.ExecuteTaskAsync<List<Result>>(request);
return results.Data;
}
}
Next, since the form load is an event handler, you can make that async as well and load the data.
public Form1() {
InitializeComponent();
}
private async void Form1_Load(object sender, EventArgs e) {
//On UI thread
resultsLoadedLabel.Text = "Loading data!";
//get data on separate thread (non blocking)
List<Result> results = await GetResults.GetDataAsync("http://worldcup.sfg.io/teams/results/");
//Back on UI thread
resultsLoadedLabel.Text = "Podaci učitani!";
foreach (var result in results) {
ResultBox.Items.Add(result.Fifa_Code);
}
}
Making sure when accessing UI controls while using async calls that they are accessed on the main thread that created them (see comments).
Data Grid View : System.InvalidOperationException: 'Cross-thread operation not valid: Control ''
The problem is on the MessageBox.Show
. You can't change UI from a background thread. in order to do that you need to Invoke
(as you said) the MessageBox.Show
from the Principal Thread.
Change your MessageBox line for (assuming that that piece of code is inside a Windows Form):
InvokeIfRequired(() =>
{
MessageBox.Show("You Enter Less Than 6 Numbers!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
});
private void InvokeIfRequired(Action method)
{
if (this.InvokeRequired)
{
Invoke(method);
}
}
c# - Cross-thread operation not valid ListView
This is because of Thread affinity of controls. Those can be updated only on thread they were created. InvokeRequired
and Invoke
gives method to update the control on same thread:
if (listView1.InvokeRequired)
{
listView1.Invoke((MethodInvoker) delegate()
{
ListViewItem item = new ListViewItem(items);
listView1.Items.Add(item);
listView1.EnsureVisible(listView1.Items.Count - 1);
});
}
Related Topics
What Does Initializecomponent() Do, and How Does It Work in Wpf
Deserializing JSON into an Object
Ignoring a Class Property in Entity Framework 4.1 Code First
What's the Difference Between Task.Start/Wait and Async/Await
Convert Integers to Written Numbers
Using C# to Check If String Contains a String in String Array
Allow Windows Service to Interact with Desktop
Using Linq to Group a List of Objects into a New Grouped List of List of Objects
Can't View Designer When Coding a Form in C#
How to Move Mouse Cursor Using C#
Delegate Keyword VS. Lambda Notation