Andry
Andry

Reputation: 16865

WPF interface is updated only after the DispatcherTimer thread finishes

I have a WPF application and I am working with the .NET Framework 4.0 and C#. My application consists of an interface with several controls. In particular I have a task that needs to be executed periodically every 10 seconds. In order to execute it I use a System.Windows.Threading.DispatcherTimer. The ViewModel looks like this:

public class WindowViewModel {
  protected DispatcherTimer cycle;

  public WindowViewModel() {
    this.cycle = new DispatcherTimer(DispatcherPriority.Normal, 
                 System.Windows.Application.Current.Dispatcher);
    this.cycle.Interval = new TimeSpan(0,0,0,0,10000);
    this.cycle.Tick += delegate(object sender, EventArgs e) {
      for (int i = 0; i < 20; i++) {
        // Doing something
      }
    };
    this.cycle.Start;
  }
}

As I said the routine called periodically does something. In particular there is some heavy logic there which causes that routine to take some seconds to execute and complete. Well it is a different thread so I should be ok and the interface is not supposed to freeze.

The problem is that that routine causes the viewmodel to be updated. Several data are updated, and the corresponding View is bound to those data. What happens is that all updated data are refreshed once at a time when the routine completes. I want data to be updated during the thread execution.

In particular inside that routine I have a for cycle. Well at the exit of the cycle everything is updated in the interface. How to achieve this? Where am i doing wrong?

Upvotes: 1

Views: 2160

Answers (1)

spender
spender

Reputation: 120508

The DispatcherTimer uses the supplied Dispatcher to run the timer callback.

If you take a look at the docs for Dispatcher, there's a clue:

Provides services for managing the queue of work items for a thread.

So, by using the System.Windows.Application.Current.Dispatcher, you're using the Dispatcher that manages "the queue of work items" for the UI thread.

To run your work in the ThreadPool instead, you could either use System.Threading.Timer or use ThreadPool.QueueUserWorkItem in your DispatcherTimer callback.

If you combine this with the following extension method, it becomes easy to marshal any UI specific stuff back to the Dispatcher when you finish your heavy workload:

public static class DispatcherEx
{
    public static void InvokeOrExecute(this Dispatcher dispatcher, Action action)
    {
        if (dispatcher.CheckAccess())
        {
            action();
        }
        else
        {
            dispatcher.BeginInvoke(DispatcherPriority.Normal,
                                   action);
        }
    }
}

then...

this.cycle.Tick += delegate(object sender, EventArgs e) {
  ThreadPool.QueueUserWorkItem(_ => {
     for (int i = 0; i < 20; i++) {
       // Doing something heavy
       System.Windows.Application.Current.Dispatcher.InvokeOrExecute(() => {
          //update the UI on the UI thread.
       });
     }
  });
};

Upvotes: 2

Related Questions