47

I tried to use the below code to make a 2 second delay before navigating to the next window. But the thread is invoking first and the textblock gets displayed for a microsecond and landed into the next page. I heard a dispatcher would do that.

Here is my snippet:

tbkLabel.Text = "two mins delay";
Thread.Sleep(2000);
Page2 _page2 = new Page2();
_page2.Show();
Milap
  • 6,915
  • 8
  • 26
  • 46
BharathNadadur
  • 557
  • 1
  • 6
  • 13

2 Answers2

118

The call to Thread.Sleep is blocking the UI thread. You need to wait asynchronously.

Method 1: use a DispatcherTimer

tbkLabel.Text = "two seconds delay";

var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
timer.Start();
timer.Tick += (sender, args) =>
    {
        timer.Stop();
        var page = new Page2();
        page.Show();
    };

Method 2: use Task.Delay

tbkLabel.Text = "two seconds delay";

Task.Delay(2000).ContinueWith(_ => 
   { 
     var page = new Page2();
     page.Show();
   }
);

Method 3: The .NET 4.5 way, use async/await

// we need to add the async keyword to the method signature
public async void TheEnclosingMethod()
{
    tbkLabel.Text = "two seconds delay";

    await Task.Delay(2000);
    var page = new Page2();
    page.Show();
}
Paul Groke
  • 6,259
  • 2
  • 31
  • 32
Phil
  • 42,255
  • 9
  • 100
  • 100
  • Method 1 might show the new page multiple times in case the timer ticks multiple times and the app is too slow handling the first one. – usr Mar 24 '13 at 15:12
  • 3
    @usr Actually it won't. Internally the timer is a single shot and is restarted after raising the Tick event. – Phil Mar 24 '13 at 15:18
  • @usr, well I didn't know. I took a peek with Resharper :) – Phil Mar 24 '13 at 15:21
  • @Phil Method 1 works fine.. but in method 2 the task does not have the delay property in wpf it seems. BTW i'm using framework3 and vs 2010.. – BharathNadadur Mar 24 '13 at 18:54
  • 2
    Also I have found this does the same: tbkLabel.Text = "two mins de lay"; Dispatcher.Invoke(new Action(() => Thread.Sleep(2000)),DispatcherPriority.Background); Page2 _page2 = new Page2(); _page2.Show(); – BharathNadadur Mar 24 '13 at 18:56
  • 11
    Just for the record, `Task.Delay()` is unfortunately also a .NET 4.5 method. – acraig5075 Sep 17 '13 at 10:20
  • How would you modify the first method to add a countdown timer that displays seconds left to page switch? – lahjaton_j Jan 05 '16 at 06:55
  • @lahjaton_j either backgroundworker, or async workflow waiting, sending notifications / triggering events, and counting down ... – Miloslav Raus May 09 '18 at 17:29
  • 2
    Wouldn't you need to dispatch `page.show()` in Method 2? – ymbcKxSw Aug 30 '18 at 15:14
1

Method 4: .NET 5.0+

    Task.WaitAll(new Task[] { Task.Delay(2000) });

This solution has no downsides. It can be used in loops which is for "DispatcherTimer" and "ContinueWith" impossible.