Question

I refactored my WPF code recently and now my DispatcherTimer stopped firing. I checked other similar posts here, but they all seemed to be problems with having the wrong dispatcher thread set, which I tried...

My code looks like this:

class MainWindow : Window
{
    private async void GoButton_Click(object sender, RoutedEventArgs e)
    {
        Hide();

        m_files = new CopyFilesWindow();
        m_files.Show();

        m_dispatcherTimer = new DispatcherTimer();
        m_dispatcherTimer.Tick += dispatcherTimer_Tick;
        m_dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 250);
        m_dispatcherTimer.Start();

        await SomeLongRunningTask();

        m_files.Hide();
        Show();
    }

(The current class is my main Window object, which I hide for the duration of file copying. CopyFilesWindow is a simple Xaml window that contains controls I modify...CopyFilesWindow does absolutely nothing itself.)

Basically, I await a long running task (copying a bunch of large files), and my DispatcherTimer is supposed to update the progress in dispatcherTimer_Tick. However, I set a breakpoint on that function and it doesn't get hit.

I have also tried setting the Dispatcher with the constructor like so:

        m_dispatcherTimer = new DispatcherTimer(DispatcherPriority.Normal, m_files.Dispatcher);
        m_dispatcherTimer = new DispatcherTimer(DispatcherPriority.Normal, this.Dispatcher);

But neither of these things change the behavior...it still doesn't fire.

What am I doing wrong here?

Was it helpful?

Solution

The DispatcherTime runs on the ... Dispatcher thread. Which is stuck waiting SomeLongRunningTask() to finish.

Indeed, when you press the button Go, it is the dispatcher thread which executes GoButton_Click. Thus, you should never make a method called by UI (the dispatcher thread) async.

private void GoButton_Click(object sender, RoutedEventArgs e)
{
    Hide();

    m_files = new CopyFilesWindow();
    m_files.Show();

    m_dispatcherTimer = new DispatcherTimer();
    m_dispatcherTimer.Tick += dispatcherTimer_Tick;
    m_dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 250);
    m_dispatcherTimer.Start();

    SomeLongRunningTask.ContinueWith(() => 
    {
        // Executes this once SomeLongRunningTask is done (even if it raised an exception)
        m_files.Hide();
        Show();
    }, TaskScheduler.FromCurrentSynchronizationContext());  // This paramater is used to specify to run the lambda expression on the UI thread.
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top