How to call a control method from another thread

后端 未结 2 390
别那么骄傲
别那么骄傲 2021-01-26 07:46

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

相关标签:
2条回答
  • 2021-01-26 08:43

    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();
    }
    
    0 讨论(0)
  • 2021-01-26 08:46

    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.

    0 讨论(0)
提交回复
热议问题