user2121001
user2121001

Reputation: 3

Appending To TextBox From Another Class and Thread C#

I have a form that sets up and displays the text box. In the form load method, I am starting a new thread from a completely separate class name Processing:

    private void Form1_Load(object sender, EventArgs e)
    {
        Processing p = new Processing();
        Thread processingThread = new Thread(p.run);
        processingThread.Start();
    }

Here is the processing class. What I would like to do is create a method in Utilities class that will allow me to update the text box from whatever class I would need to:

public class Processing
{        
    public void run()
    {               
        Utilities u = new Utilities();

        for (int i = 0; i < 10; i++)
        {
            u.updateTextBox("i");
        }                    
    }

 }

Then finally the Utilites class:

class Utilities
{
    public void updateTextBox(String text) 
    {
        //Load up the form that is running to update the text box
        //Example:  
        //Form1.textbox.appendTo("text"):
    }
}

I have read about the Invoke methods, SynchronizationContext, Background threads and everything else, but almost all examples are using methods in the same class as the Form thread, and not from separate classes.

Upvotes: 0

Views: 10244

Answers (2)

Servy
Servy

Reputation: 203844

The Progress class is designed specifically for this.

In your form, before starting the background thread, create a Progress object:

Progress<string> progress = new Progress<string>(text => textbox.Text += text);

Then provide that progress object to your worker method:

Processing p = new Processing();
Thread processingThread = new Thread(() => p.run(progress));
processingThread.Start();

Then the processor can report the progress:

public class Processing
{        
    public void run(IProgress<string> progress)
    {               
        for (int i = 0; i < 10; i++)
        {
            Thread.Sleep(1000);//placeholder for real work
            progress.Report("i");
        }                    
    }
}

The Progress class, internally, will capture the synchronization context where it was first created and marshall all event handlers invoked as a result of the Report calls to that context, which is just a fancy way of saying it takes care of moving to the UI thread on your behalf. It also ensures that all of your UI code stays inside the definition of the Form, and all of the non-UI code it outside of the form, helping separate business code from UI code (which is a very good thing).

Upvotes: 3

Katie Kilian
Katie Kilian

Reputation: 6983

I would add a AppendText() method to your Form1 class, like this:

public void AppendText(String text) 
{
    if (this.InvokeRequired)
    {
        this.Invoke(new Action<string>(AppendText), new object[] { text });
        return;
    }
    this.Textbox.Text += text;
}

Then from your utility class, call it like this:

class Utilities
{
    Form form1;   // I assume you set this somewhere

    public void UpdateTextBox(String text) 
    {
        form1.AppendText(text);
    }
}

There is a very good comprehensive review of threading in .NET that can be found here: Multi-Threading in .NET. It has a section on Threading in WinForms that would help you a lot.

Upvotes: 2

Related Questions