views:

84

answers:

3

Hello

I've been researching on how to do this for about a week and I'm still not sure about the correct approach, in some examples I see the Thread class is used in others I see Invoke is used which has confused me a bid.

I have a GUI program in c# which contains a textBox which will be used to give information to the user.

The problem I'm facing is that I'm not sure how I can append text to textBox from another class which is running on another thread. If someone can show me a working example, it would help me greatly.

Best Regards!

A: 

Sounds like you're using a background thread for processing, but want to keep the UI responsive? The BackgroundWorker sounds like the ticket:

The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution.

Pierreten
I dont understand the relevance of the BackgroundWorker here - he already is running on another thread...
Mrk Mnl
This answer won't be understood until you explain how the event handlers run on the main thread.
Hans Passant
A: 

Just use BackgroundWorker for the same. It is simple and takes away the pain of managing threads of your own. for more, you can see: http://dotnetperls.com/backgroundworker

Kangkan
Background worker is a thread from the thread pool, and as such is not an STA thread, so you won't be able to do a lot of UI related things from it, aside from throwning events.
Aurélien Ribon
I dont understand the relevance of the BackgroundWorker here - he already is running on another thread..
Mrk Mnl
+5  A: 

Easy:

MainWindow.myInstance.Dispatcher.BeginInvoke(new Action(delegate() {MainWindow.myInstance.myTextBox.Text = "some text";});

WHERE MainWindow.myInstance is a public static variable set to the an instance of MainWindow (should be set in the constructor and will be null until an instance is constructed).

Ok thats a lot in one line let me go over it:

When you want to update a UI control you, as you say, have to do it from the UI thread. There is built in way to pass a delegate (a method) to the UI thread: the Dispatcher. I used MainWindow.myInstance which (as all UI components) contains reference to the Dispatcher - you could alternatively save a reference to the Dispatcher in your own variable:

Dispatcher uiDispatcher = MainWindow.myInstance.Dispatcher;

Once you have the Dispatcher you can either Invoke() of BeginInvoke() passing a delegate to be run on the UI thread. The only difference is Invoke() will only return once the delegate has been run (i.e. in your case the TextBox's Text has been set) whereas BeginInvoke() will return immediately so your other thread you are calling from can continue (the Dispatcher will run your delegate soon as it can which will probably be straight away anyway).

I passed an anonymous delegate above:

delegate() {myTextBox.Text = "some text";}

The bit between the {} is the method block. This is called anonymous because only one is created and it doesnt have a name - but I could instantiated a delegate:

Action myDelegate = new Action(UpdateTextMethod);

void UpdateTextMethod() 
{
    myTextBox.Text = "new text";
}

Then passed that:

uiDispatcher.Invoke(myDelegate);

I also used the Action class which is a built in delegate but you could have created your own - you can read up more about delegates on MSDN as this is going a bit off topic..

Mrk Mnl
That's totally the right answer. Note however that BeginInvoke will add your delegate action into a queue, and so the UI will be updated "when it cans". As a result, do everyhting that should be ordered in the delegate.
Aurélien Ribon
Another comment: BeginInvoke is a method which parameters changed when framework 3.5 was out, so IntelliSense documentation is not correct about them (look for it on google, everybody rages about it). You can pass a priority to help the UI decide if if should update now or if it is not so important with `BeginInvoke(DispatcherPriority.Render, new Action(yourDelegate))`.
Aurélien Ribon
Yes - even with Invoke() the delegate will be put on the queue though the queue should (to keep the UI responsive) only contain small fast processes which is why I said will probably be straight away anyway..
Mrk Mnl
Yes you can specify priority but it is optional (the method is overloaded) and 99% of the time the default: DispatcherPriority.Normal, is what you want anyway.
Mrk Mnl
Thanks, but it seems the Dispatcher class is not available for me. Do I have to add a reference in order to use it?
Arya
What GUI application are you developing? Windows Forms? WPF?
Mrk Mnl
Windows Forms Application
Arya
I was just reading about WPF, I think its much better than Windows forms, and yes the Dispatcher class is available for it too, I will convert my project to WPF tomorrow and try what you suggested.
Arya
@Mrk-Mnl I changed my project to WPF and start a Thread with the following code private void button1_Click(object sender, RoutedEventArgs e) { Class1 c = new Class1(); Thread t = new Thread(c.test); t.IsBackground = true; t.Start(); }and here is my c.test method public void test() { Thread.Sleep(9999); MessageBox.Show("DONE"); Application.Current.MainWindow.Dispatcher.BeginInvoke(new Action(delegate() {textBox1.Text = "some text";}); }But it does not have access to textBox1, I'm sorry I keep asking, I'm new to threading.
Arya