views:

62

answers:

2

Hi everyone,

I've been reading a lot about threading in C#, WPF and Silverlight but can't get it to work.

My main problem is I have the _load (_Initialized) action and it has a lot of object creation and along with that I have timers working doing different things, this causes the startup time of the program to be very slow and obviously causes the UI to hang and it isn't a good thing for deploying to a lot of users.

My timers change values of labels and textfields but having them do that on another thread is an obvious no go.

So can someone give me some examples on how to achieve what I need to do?

Thanks

+2  A: 

Push your work onto other threads, and use Dispatcher.Invoke to marshal the setting of labels and text fields back onto your UI thread.

That being said, if you can, you can also refactor your work to use the BackgroundWorker class. The progress and completion events are already marshaled back onto the UI thread, so it makes it easier to update the UI in many situations.

Reed Copsey
Ahem. I do think you meant Dispatcher.Invoke. Rollback if you disagree.
Henk Holterman
@Henk: Either can be used. I often use BeginInvoke instead of Invoke if I'm just setting labels or other similar things, since there's no reason to wait on the operation to complete. - http://msdn.microsoft.com/en-us/library/ms591206.aspx
Reed Copsey
Yes, my mistake. I saw a few Delegate.BeginInvokes in similar answers lately.
Henk Holterman
Thanks for the info, is it possible if you can give me sample code?
Sandeep Bansal
+1 for backgroundworker. It's mad easy to use.
Pierreten
@sandip, the linked msdn docs give you tons of sample code. Please look at them first.
Pierreten
Just found them, thanks a lot
Sandeep Bansal
A: 

The trick is that your UI logic has to execute on the UI thread. There are methods provided that make this easier than it might otherwise be, but using them can be tricky. Here's how I've done it in the past:

First, you have to declare a delegate that you can feed to the Dispatcher.Invoke method:

private delegate void UIDelegate();

Then you can get your background worker setup and call it's RunWorkerAsync method:

BackgroundWorker loadWorker = new BackgroundWorker();
loadWorker.DoWork += new DoWorkEventHandler(loadWorker_DoWork);
loadWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(loadWorker_RunWorkerCompleted);
loadWorker.RunWorkerAsync();

Then, to update UI elements, you have to invoke their dispatcher:

private void changeStatusLabel(string status)
{
    progressLabel.Dispatcher.Invoke(new UIDelegate(delegate
    {
        progressLabel.Content = status;
    }));
}

These are cut from larger methods and they can likely be optimized a bit. Still, that'll give you a place to start from.

Jacob Proffitt
Thanks for all the info, I gave it a try but what goes in the loadWorker_DoWork()? what if I have a label which is like this: this.label.Content = getCurrentUsage().ToString(); How can I put everything in how it would be in a Timer.
Sandeep Bansal
The loadWorker_DoWork is exactly the same as your timer event and is where you'd need to use Dispatcher.Invoke to update the UI.
Jacob Proffitt
Or you can use the progress-reporting delegate of the BackgroundWorker, which runs on the UI thread for just this purpose.
Robert Rossney
Great stuff you just helped me make threading so much easier to code than I thought. As a note, I used while(true) in the doWork to make it act as a timer.
Sandeep Bansal