Search code examples
c#.netmultithreadingtextboxbackgroundworker

Accessing functions across threads


I am working on a program which uses a backgroundWorker to append text to a Textbox control. My problem is that simply, the backgroundWorker will not insert text into the Textbox control, it just remains blank.

My code:

private void button1_Click(object sender, EventArgs e) {
    backgroundWorker1.RunWorkerAsync(); //Start the worker
}

public void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
    this.writeText("Hello World!");
}

public void writeText(string text) {
    textbox1.Text = textbox1.Text + text + "\r\n";
    textbox1.SelectionStart = textbox1.Text.Length;
    textbox1.ScrollToCaret();        //Scroll to the end of the textbox
}


Looking at the code, it seems fine (to me anyway) and it compiles fine too, so it's probably something very obvious that I am missing.

If someone would care to enlighten me on what I am doing wrong, it would be much appreciated ;)


Solution

  • You can declare a delegate at the class level for your Form.

    public delegate void WriteLogEntryDelegate(string log_entry);
    

    You can then wrap up most of the logic in another method:

    void WriteLogEntryCB(string log_entry)
        {
            if (textbox1.InvokeRequired == true)
                    {
                        var d = new WriteLogEntryDelegate(WriteLogEntryCB);
                        this.Invoke(d, log_entry);
                    }
                    else
                    {
                        textbox1.Text(log_entry + "\r\n");
                        this.textbox1.SelectionStart = this.textbox1.Text.Length;
                        this.textbox1.ScrollToCaret();
                    }
        }
    

    You can then call that Function from your DoWork Method:

    public void DoWork(object sender, DoWorkEventArgs e) 
    {
        WriteLogEntryCB("Hello World!");
    }
    

    Edit to Include Daniel Mann's Suggestion: Another way would be to cast the sender in the DoWork method as the BackgroundWorker, and then call the ReportProgress Method (or use the RunWorkerCompleted Event Handler).

    void bw1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            worker.ReportProgress((1));
        }
    

    You would then require an event handler for the ProgressChanged Event:

    void bw1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //update textbox here
        }
    

    Finally, you could also use the RunWorkerCompleted Event Handler:

    void bw1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
           //update textbox here
        }