I hit a problem and I thought it might be due to the complexity of my classes passing objects to each other so I minimised it and the problem persists:
I've got a default winform project created in VS2017 Community
On the form I've added a textbox, a richtextbox, a backgroundworker and a button to activate the background worker.
I've put the following code in the form to populate the text boxes and to run the worker on button click:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
textBox1.Text = "Hello";
richTextBox1.Text = "World!";
}
private void button1_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
MessageBox.Show(textBox1.Text);
MessageBox.Show(richTextBox1.Text);
}
}
I run the program and I don't understand what happens next.
textBox1.Text is accessible from the form so the MessageBox shows fine. richTextBox1.Text is NOT accessible and gives me this error:
Cross-thread operation not valid: Control 'richTextBox1' accessed from a thread other than the thread it was created on.
WHY?
I'm assuming richTextBox has more routing and wrapping but is the .Text property not exactly the same?! What's going on here?
EDIT: I don't think this is a duplicate to the marked question because his wasn't working for TextBox.Text whereas mine is. I'm asking about the DIFFERENCE BETWEEN TextBox and RichTextBox .Text properties.
They have been implemented differently.
TextBox.Text basically returns Control.Text which calls WindowText which uses GetWindowText.
in the code comments clearly mentioned it's okay to call GetWindowText cross-thread. So they've turned off checking for cross-thread on purpose by setting a flag inCrossThreadSafeCall.
But for ReachTextBox.Text it doesn't rely on Control.Text. It sends EM_STREAMOUT and uses the result. So no flag has been set to except this from cross-thread exception.
Note: You should ignore such cases and you should never try to access UI element from another thread. Always use Invoke method of the control when you are trying to interact with UI thread from another thread.
You have to Invoke UI code (you can't run UI in the thread other than UI):
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// What to do with UI
Action action = () => {
MessageBox.Show(textBox1.Text);
MessageBox.Show(richTextBox1.Text);
}
if (InvokeRequired) // We are in some background thread, Invoke required
Invoke(action);
else // We are in UI (main) thread, just call the action
action();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With