Search code examples
c#multithreadingbackgroundworker

Get richtextbox.text from another thread


I can't believe this hasn't been asked before but I can't find a reference here. Sorry if I've missed it!! There's plenty on updating rtb.Text from a thread but little or none on getting rtb.Text.

I need to get the text value from a richtextbox on the UI thread from another thread and later be able to loop through each line of the same richtextbox.

I guess Invokes and Delegates are required but how to craft them??

As an example the code, if it was in the same thread, would be something like:

private void checkRtbEntries()
{
    if (rtb.Text != "")
    {
        foreach (string textLine in rtb.Lines)
        {
            // do some things in the background thread 
            // based on the rtb line content...
        }
    }
}

But, checkRtbEntries() is called from within a Backgroundworker thread and rtb is in the UI thread, hence a Cross-thread operation not valid is thrown.


Solution

  • When you run your BackgroundWorker thread, you have the option of passing an argument to it, which the other thread can reference and use:

    myWorker.RunWorkerAsync(rtb.Text);
    

    Inside the DoWork event, cast the argument back to a string and perform your actions on it.

    var myRtbText = e.Argument.ToString();
    

    This way, your background thread never actually touches the UI thread.

    If you need to make changes to an element back on the main thread while your background worker is running, you'll need to use the ProgressChanged event.

    Since you don't have a reference to the RichTextBox in the DoWork event (just the contents of its Text property), you can't actually call the Lines property on the original text box.

    You should be able to simulate it pretty easily though (the actual Lines property tests for "\r", "\r\n", and "\n", but Environment.NewLine should take care of figuring that out for you):

    var allLines
        = myRtbText.Split(new[] {Environment.NewLine}, StringSplitOptions.None);
    

    (Or use StringSplitOptions.RemoveEmptyEntries if you want to ignore blank lines.)