views:

283

answers:

4

Hi

I'm building a single window WPF application In the window is a list items (which are persisted in a database of course) Periodically I need to start a background task that updates the database from an Atom feed. As each new item is added to the database, the list in the UI must also update to reflect this. I don't want this background task to slow down the UI but at the same time it needs to interact with the UI.

Having read loads of articles and seen lots of simple examples, I am still unsure of the best way to implement this.

What I think maybe I could do is:

On the Window_Loaded event, create a DispatchTimer. When the Tick event fires, call UpdateDb() method. UpdateDB() will get the items from the Atom feed and add to the database. As I iterate through each item I will call another method to rebind the list to the database so that it "refreshes". When all the tasks are finished reset the DispatchTimer ??? (not sure if this can / needs to be / done).

Remember, this is background task so a user could be using the UI at the same time.

How does this sound?

Thanks.

A: 

Your approach would work.

You'd start the timer when the app loads. For each tick of the timer, you start a thread to update the database. Once the database update has happened, you can call .BeginInvoke() on your UI objects to update the UI on the presentation thread (that will be the only time your UI should be affected).

Justin Niessner
If all the DispatcherTimer does is kick off another thread, what is the point of using the DispatcherTimer?
Kent Boogaart
Because the thread that it kicks off can do the heavy lifting of updating the database without blocking the UI thread...and the DispatchTimer will start these threads on a schedule rather than one off.
Justin Niessner
Yes, but those threads don't need to be started on the UI thread. You could just use a regular Timer and avoid interrupting the UI altogether ;)
Kent Boogaart
Doh...good call. It's not noon yet here. My brain hasn't quite finished the boot-up process yet...
Justin Niessner
+2  A: 

This sounds suboptimal because you're doing database connectivity on the UI thread. When the Tick event fires on the DispatcherTimer, handlers will execute on the UI thread. You need to minimize the amount of work you do on this thread to keep the UI responsive, and you definitely shouldn't be doing IO-bound work on this thread.

I would probably have a data service whose responsibility is to update the database and raise events as changes are made. Your UI layer can attach to these events and marshal to the UI thread to apply changes. To marshal to the UI thread, you just need to call Dispatcher.Invoke.

Regardless of your specific approach, the key is to do as much as you can (including any database access) on a separate thread. Marshal back to the UI thread as late as possible and do as little work as possible on the UI thread.

One other thing to note is that WPF automatically marshals changes to scalar values for you. You only need to marshal changes to collections (adding/removing/replacing items).

HTH, Kent

Kent Boogaart
I like the sound of this. I don't need a data service though as I have already have a manager class to handle db work. No db work is happening in the UI. I was just trying to simplyfy the background info of my problem.
empo
A: 

I'd use a System.Threading.Timer, which will call a specified method at a specified interval on a threadpool thread, so no need to create an additional thread, do your db work with that and marshal back to the ui thread as needed.

Matt
A: 

WPF Multithreading with BackgroundWorker by Pavan Podila:

The good news is that you really don’t have to write such a component since one is available already: the BackgroundWorker class introduced in .Net Framework 2.0. Programmers who are familiar with WinForms 2.0 may have already used this component. But BackgroundWorker works equally well with WPF because it is completely agnostic to the threading model.

rasx
I don't think this would work for me because I need to access UI objects whilst the task is running. I think an exception would be thrown because of trying to access the UI from another thread.
empo
Take a look at "Background worker in C# - Threading Made Easy" (http://www.nerdparadise.com/tech/coding/csharp/backgroundworker/) and see how the ProgressChangedEventHandler() can't work for you.
rasx