How to call a control method from another thread

左心房为你撑大大i 提交于 2019-12-20 07:36:21

问题


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 my form. I want to update it from another thread. I was able to change its properties using Invoke. But can't figure out how to call _ucResultRich.rchResult.Find(word, startIndex, RichTextBoxFinds.None); from my thread.

Thread thread=new Thread(thrHighlight);
thread.Start(e.RowIndex);

private void ThrHighlight(object obj)
{
    string[] words = ucSearchControls.rdbExact.Checked
          ? new string[] { ucSearchControls.txtSearch.Text.Trim() }
              : ucSearchControls.txtSearch.Text.Split(' ');
    foreach (string word in words)
    {
        int startIndex = 0;
        while (startIndex < _ucResultRich.rchResult.TextLength)
        {

            int wordStartIndex = _ucResultRich.rchResult.Find(word, startIndex, RichTextBoxFinds.None);
            if (wordStartIndex != -1)
            {
                _ucResultRich.rchResult.SelectionStart = wordStartIndex;
                _ucResultRich.rchResult.SelectionLength = word.Length;
                _ucResultRich.rchResult.SelectionBackColor = Color.Yellow;
            }
            else
            break;
            startIndex += wordStartIndex + word.Length;
        }
    }
}

How can I do that?

P.S: This is the follow-up to my first question and to the @varocarbas comments there


回答1:


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();
}



回答2:


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.



来源:https://stackoverflow.com/questions/34153497/how-to-call-a-control-method-from-another-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!