Wait some seconds without blocking UI execution

C#TimerWait

C# Problem Overview


I would like to wait some seconds between two instruction, but WITHOUT blocking the execution.

For example, Thread.Sleep(2000) it is not good, because it blocks execution.

The idea is that I call a method and then I wait X seconds (20 for example) listening for an event coming. At the end of the 20 seconds I should do some operation depending on what happened in the 20 seconds.

C# Solutions


Solution 1 - C#

I think what you are after is Task.Delay. This doesn't block the thread like Sleep does and it means you can do this using a single thread using the async programming model.

async Task PutTaskDelay()
{
    await Task.Delay(5000);
} 

private async void btnTaskDelay_Click(object sender, EventArgs e)
{
    await PutTaskDelay();
    MessageBox.Show("I am back");
}

Solution 2 - C#

I use:

private void WaitNSeconds(int segundos)
{
    if (segundos < 1) return;
    DateTime _desired = DateTime.Now.AddSeconds(segundos);
    while (DateTime.Now < _desired) {
         System.Windows.Forms.Application.DoEvents();
    }
}

Solution 3 - C#

This is a good case for using another thread:

// Call some method
this.Method();

Task.Factory.StartNew(() =>
{
    Thread.Sleep(20000);

    // Do things here.
    // NOTE: You may need to invoke this to your main thread depending on what you're doing
});

The above code expects .NET 4.0 or above, otherwise try:

ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
{
    Thread.Sleep(20000);

    // Do things here
}));

Solution 4 - C#

Omar's solution is decent* if you cannot upgrade your environment to .NET 4.5 in order to gain access to the async and await APIs. That said, there here is one important change that should be made in order to avoid poor performance. A slight delay should be added between calls to Application.DoEvents() in order to prevent excessive CPU usage. By adding

Thread.Sleep(1);

before the call to Application.DoEvents(), you can add such a delay (1 millisecond) and prevent the application from using all of the cpu cycles available to it.

private void WaitNSeconds(int seconds)
{
    if (seconds < 1) return;
    DateTime _desired = DateTime.Now.AddSeconds(seconds);
    while (DateTime.Now < _desired) {
         Thread.Sleep(1);
         System.Windows.Forms.Application.DoEvents();
    }
}

*See https://blog.codinghorror.com/is-doevents-evil/ for a more detailed discussion on the potential pitfalls of using Application.DoEvents().

Solution 5 - C#

If you do not want to block things and also not want to use multi threading, here is the solution for you: https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx

The UI Thread is not blocked and the timer waits for 2 seconds before doing something.

Here is the code coming from the link above:

        // Create a timer with a two second interval.
    aTimer = new System.Timers.Timer(2000);
    // Hook up the Elapsed event for the timer. 
    aTimer.Elapsed += OnTimedEvent;
    aTimer.Enabled = true;

    Console.WriteLine("Press the Enter key to exit the program... ");
    Console.ReadLine();
    Console.WriteLine("Terminating the application...");

Solution 6 - C#

i really disadvise you against using Thread.Sleep(2000), because of a several reasons (a few are described here), but most of all because its not useful when it comes to debugging/testing.

I recommend to use a C# Timer instead of Thread.Sleep(). Timers let you perform methods frequently (if necessary) AND are much easiert to use in testing! There's a very nice example of how to use a timer right behind the hyperlink - just put your logic "what happens after 2 seconds" right into the Timer.Elapsed += new ElapsedEventHandler(OnTimedEvent); method.

Solution 7 - C#

hi this is my suggestion

 .......
var t = Task.Run(async () => await Task.Delay(TimeSpan.FromSeconds(Consts.FiveHundred)).ConfigureAwait(false));
                //just to wait task is done
                t.Wait();

keep in mind put the "wait" otherwise the Delay run without affect application

Solution 8 - C#

If possible, the preferred approach should be using an asynchronous way or a second thread.

If this isn't possible or wanted, using any implementation of DoEvents() is a bad idea, since it may cause problems Possible problems with DoEvents. This is mostly about DoEvents with Winforms but the possible pitfalls in WPF are the same.

Then putting a frame on the Dispatcher with the wanted sleep time can be used:

using System;
using System.Threading;
using System.Windows.Threading;

public static void NonBlockingSleep(int timeInMilliseconds)
{
	DispatcherFrame df = new DispatcherFrame();

	new Thread((ThreadStart)(() =>
	{
		Thread.Sleep(TimeSpan.FromMilliseconds(timeInMilliseconds));
		df.Continue = false;

	})).Start();

	Dispatcher.PushFrame(df);
}

Solution 9 - C#

In my case I needed to do this because I had passed a method to the thread I was waiting for and that caused the lock becuase the metod was run on the GUI thread and the thread code called that method sometimes.

Task<string> myTask = Task.Run(() => {
    // Your code or method call
    return "Maybe you want to return other datatype, then just change it.";
});
// Some other code maybe...
while (true)
{
    myTask.Wait(10);
    Application.DoEvents();
    if (myTask.IsCompleted) break;
}

Solution 10 - C#

using System.Windows.Forms.Timer

new Timer
{
    Enabled = true,
    Interval = 5000
}.Tick += (s, e) =>
{
    ((Timer)s).Enabled = false;
    
    MessageBox.Show("Hello Timer!");
};

Solution 11 - C#

Look into System.Threading.Timer class. I think this is what you're looking for.

The code example on MSDN seems to show this class doing very similar to what you're trying to do (check status after certain time).

The mentioned code example from the MSDN link:

using System;
using System.Threading;

class TimerExample
{
    static void Main()
    {
        // Create an AutoResetEvent to signal the timeout threshold in the
        // timer callback has been reached.
        var autoEvent = new AutoResetEvent(false);
        
        var statusChecker = new StatusChecker(10);

        // Create a timer that invokes CheckStatus after one second, 
        // and every 1/4 second thereafter.
        Console.WriteLine("{0:h:mm:ss.fff} Creating timer.\n", 
                        DateTime.Now);
        var stateTimer = new Timer(statusChecker.CheckStatus, 
                                autoEvent, 1000, 250);

        // When autoEvent signals, change the period to every half second.
        autoEvent.WaitOne();
        stateTimer.Change(0, 500);
        Console.WriteLine("\nChanging period to .5 seconds.\n");

        // When autoEvent signals the second time, dispose of the timer.
        autoEvent.WaitOne();
        stateTimer.Dispose();
        Console.WriteLine("\nDestroying timer.");
    }
}

class StatusChecker
{
    private int invokeCount;
    private int  maxCount;

    public StatusChecker(int count)
    {
        invokeCount  = 0;
        maxCount = count;
    }

    // This method is called by the timer delegate.
    public void CheckStatus(Object stateInfo)
    {
        AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
        Console.WriteLine("{0} Checking status {1,2}.", 
            DateTime.Now.ToString("h:mm:ss.fff"), 
            (++invokeCount).ToString());

        if(invokeCount == maxCount)
        {
            // Reset the counter and signal the waiting thread.
            invokeCount = 0;
            autoEvent.Set();
        }
    }
}
// The example displays output like the following:
//       11:59:54.202 Creating timer.
//       
//       11:59:55.217 Checking status  1.
//       11:59:55.466 Checking status  2.
//       11:59:55.716 Checking status  3.
//       11:59:55.968 Checking status  4.
//       11:59:56.218 Checking status  5.
//       11:59:56.470 Checking status  6.
//       11:59:56.722 Checking status  7.
//       11:59:56.972 Checking status  8.
//       11:59:57.223 Checking status  9.
//       11:59:57.473 Checking status 10.
//       
//       Changing period to .5 seconds.
//       
//       11:59:57.474 Checking status  1.
//       11:59:57.976 Checking status  2.
//       11:59:58.476 Checking status  3.
//       11:59:58.977 Checking status  4.
//       11:59:59.477 Checking status  5.
//       11:59:59.977 Checking status  6.
//       12:00:00.478 Checking status  7.
//       12:00:00.980 Checking status  8.
//       12:00:01.481 Checking status  9.
//       12:00:01.981 Checking status 10.
//       
//       Destroying timer.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser3376691View Question on Stackoverflow
Solution 1 - C#daniellepelleyView Answer on Stackoverflow
Solution 2 - C#OmarView Answer on Stackoverflow
Solution 3 - C#MattView Answer on Stackoverflow
Solution 4 - C#Nick PainterView Answer on Stackoverflow
Solution 5 - C#DaanView Answer on Stackoverflow
Solution 6 - C#Matthias R.View Answer on Stackoverflow
Solution 7 - C#lukaView Answer on Stackoverflow
Solution 8 - C#marsh-wiggleView Answer on Stackoverflow
Solution 9 - C#JonView Answer on Stackoverflow
Solution 10 - C#יהונתן אלברטView Answer on Stackoverflow
Solution 11 - C#LB2View Answer on Stackoverflow