I want to call RichTextBox.Find()
from another thread. How can I do that?
The RichTextBox
is located in a UserControl
which I\'m using in
This answer is exclusively focused on showing how to use properly (i.e., by maximising its in-built functionalities) BackgroundWorker
(it is the continuation of some of the comments I wrote in a previous post of the OP) to deliver the intended functionalities.
To use the code below these lines, start a new Winforms project and add the following controls to the main form: Button
(button1
with the click event button1
), RichTextBox
(richTextBox1
) and a BackgroundWorker
(backgroundWorker1
with the DoWork
event backgroundWorker1_DoWork
and the ProgressChanged
event backgroundWorker1_ProgressChanged
); also note that Form1_Load
is the Load
event of the main form.
To use the application, just input any text in the richTextBox1
by including some of the hardcoded words (i.e., "word1", "word2", "word3", "word4", "word5"), click on button1
and confirm that they are highlighted as expected.
volatile int curWordStartIndex; //I use this global variable to communication between the progressChanged event and findBit, called from the DoWork event
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.WorkerReportsProgress = true;
}
private void button1_Click(object sender, EventArgs e)
{
//As far as richTextBox1.TextLength provokes a cross-thread error, I pass it as an argument
backgroundWorker1.RunWorkerAsync(richTextBox1.TextLength);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
findBit((int)e.Argument);
}
private void findBit(int textLength)
{
string[] words = new string[] { "word1", "word2", "word3", "word4", "word5" };
foreach (string word in words)
{
int startIndex = 0;
while (startIndex < textLength)
{
//Rather than performing the actions affecting the GUI thread here, I pass all the variables I need to
//the ProgressChanged event through ReportProgress and perform the modifications there.
backgroundWorker1.ReportProgress(0, new object[] { word, startIndex, Color.Yellow });
if (curWordStartIndex == -1) break;
startIndex += curWordStartIndex + word.Length;
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
object[] curVars = (object[])e.UserState;
richTextBox1.SuspendLayout();
string word = (string)curVars[0];
int startIndex = (int)curVars[1];
Color curColor = (Color)curVars[2];
curWordStartIndex = richTextBox1.Find(word, startIndex, RichTextBoxFinds.None);
if (curWordStartIndex != -1)
{
richTextBox1.SelectionStart = curWordStartIndex;
richTextBox1.SelectionLength = word.Length;
richTextBox1.SelectionBackColor = curColor;
}
richTextBox1.ResumeLayout();
}
You need to decouple your code a bit from UI controls and do your business logic on external thread and update UI control on Dispatcher.BeginInvoke or Invoke.
For example ,you can save the text that your Textbox has in a separate property and do Find on other thread ,once you are done post the UI highlight part on UI thread.