9

Is there a synchronous wait function that won't tie up the UI-thread in .NET WPF? Something like:

Sub OnClick(sender As Object, e As MouseEventArgs) Handles button1.Click
     Wait(2000) 
     'Ui still processes other events here
     MessageBox.Show("Is has been 2 seconds since you clicked the button!")
End Sub
H.B.
  • 166,899
  • 29
  • 327
  • 400
PeterM
  • 2,372
  • 1
  • 26
  • 35

2 Answers2

18

You can use a DispatcherTimer for that sort of thing.

Edit: This might do as well...

private void Wait(double seconds)
{
    var frame = new DispatcherFrame();
    new Thread((ThreadStart)(() =>
        {
            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            frame.Continue = false;
        })).Start();
    Dispatcher.PushFrame(frame);
}

(Dispatcher.PushFrame documentation.)


Starting with .NET 4.5 you can use async event handlers and Task.Delay to get the same behaviour. To simply let the UI update during such a handler return Dispatcher.Yield.

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • 1
    In WPF you defiantly want to use the DispatcherTimer as it's ticks will execute on the UI's thread enabling you to modify UI controls. If you use a standard timer the ticks execute on its own thread and you will get some nasty exceptions if you try to touch UI controls. +1 – Jay May 24 '11 at 21:50
  • Is there anyway to use the timer to do the waits inline. Seems cumbersome and hard to read when you break up a method every time you need a wait. – PeterM May 24 '11 at 21:58
  • 1
    @PeterM: As i'm not all too well versed in threading issues you might want to take a look at the [Threading Model](http://msdn.microsoft.com/en-us/library/ms741870.aspx) reference and the [`Dispatcher.PushFrame`](http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.pushframe.aspx) method, which might help you simplify this. – H.B. May 24 '11 at 22:27
  • @PeterM: Actually i think i just got a solution using this method, see my updated answer. (I don't speak VB though...) – H.B. May 24 '11 at 23:03
  • As an example [A non blocking wait for event in C#](https://medium.com/home-wireless/a-non-blocking-wait-for-event-in-c-6662ba47373) – Eli Apr 15 '20 at 09:17
  • This solution works but should used with care. See [Which blocking operations cause an STA thread to pump COM messages?](https://stackoverflow.com/a/21573637/8051589) for example. Quoted from that answer: – Andre Kampling Jul 08 '20 at 10:55
1

Here is a solution with Task.Delay. I'm using it in unit-tests for ViewModels that use DispatcherTimer.

var frame = new DispatcherFrame();

var t = Task.Run(
    async () => {
        await Task.Delay(TimeSpan.FromSeconds(1.5));
        frame.Continue = false;
    });

Dispatcher.PushFrame(frame);

t.Wait();
zmechanic
  • 1,842
  • 21
  • 27