How to asynchronously wait for x seconds and execute something then?

101,818

Solution 1

(transcribed from Ben as comment)

just use System.Windows.Forms.Timer. Set the timer for 5 seconds, and handle the Tick event. When the event fires, do the thing.

...and disable the timer (IsEnabled=false) before doing your work in oder to suppress a second.

The Tick event may be executed on another thread that cannot modify your gui, you can catch this:

private System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();

    private void StartAsyncTimedWork()
    {
        myTimer.Interval = 5000;
        myTimer.Tick += new EventHandler(myTimer_Tick);
        myTimer.Start();
    }

    private void myTimer_Tick(object sender, EventArgs e)
    {
        if (this.InvokeRequired)
        {
            /* Not on UI thread, reenter there... */
            this.BeginInvoke(new EventHandler(myTimer_Tick), sender, e);
        }
        else
        {
            lock (myTimer)
            {
                /* only work when this is no reentry while we are already working */
                if (this.myTimer.Enabled)
                {
                    this.myTimer.Stop();
                    this.doMyDelayedWork();
                    this.myTimer.Start(); /* optionally restart for periodic work */
                }
            }
        }
    }

Just for completeness: with async/await, one can delay execute something very easy (one shot, never repeat the invocation):

private async Task delayedWork()
{
    await Task.Delay(5000);
    this.doMyDelayedWork();
}

//This could be a button click event handler or the like */
private void StartAsyncTimedWork()
{
    Task ignoredAwaitableResult = this.delayedWork();
}

For more, see "async and await" in MSDN.

Solution 2

Have you tried

public static Task Delay(
    int millisecondsDelay
)

You can use like this:

await Task.Delay(5000);

reference: https://msdn.microsoft.com/en-us/library/hh194873(v=vs.110).aspx

Solution 3

You can start an asynchronous task that performs your action:

Task.Factory.StartNew(()=>
{
    Thread.Sleep(5000);
    form.Invoke(new Action(()=>DoSomething()));
});

[EDIT]

To pass the interval in you simply have to store it in a variable:

int interval = 5000;
Task.Factory.StartNew(()=>
{
    Thread.Sleep(interval);
    form.Invoke(new Action(()=>DoSomething()));
});

[/EDIT]

Solution 4

You can wait UI thread the way you want it to work.

Task.Factory.StartNew(async() =>
{
    await Task.Delay(2000);

    // it only works in WPF
    Application.Current.Dispatcher.Invoke(() =>
    {
        // Do something on the UI thread.
    });
});

if you're using .Net Framework 4.5 or higher version, you can use Task.Run instead of Task.Factory.StartNew just like below.

int millisecondsDelay = 2000;

Task.Run(async() =>
{
    await Task.Delay(millisecondsDelay);

    // it only works in WPF
    Application.Current.Dispatcher.Invoke(() =>
    {
        // Do something on the UI thread.
    });
});

Solution 5

You are looking at it wrong. Click the button, it kicks off a timer with an interval of x seconds. When those are up it's eventhandler executes the task.

So what don't you want to happen.

While the x seconds are elapsing.?

While The task is executing?

If for instance it's you don't want the button to be clicked until delay and task are done. Disable it in the button click handler, and enable it on task completion.

If all you want is a five second delay prior to the task, then you should pass the start delay to the task and let it take care of it.

Share:
101,818
Dennis G
Author by

Dennis G

Click on CTRL+About me on your keyboard and you will be surprised!

Updated on April 21, 2021

Comments

  • Dennis G
    Dennis G about 3 years

    I know there is Thread.Sleep and System.Windows.Forms.Timer and Monitor.Wait in C# and Windows Forms. I just can't seem to be able to figure out how to wait for X seconds and then do something else - without locking the thread.

    I have a form with a button. On button click a timer shall start and wait for 5 seconds. After these 5 seconds some other control on the form is colored green. When using Thread.Sleep, the whole application would become unresponsive for 5 seconds - so how do I just "do something after 5 seconds"?

  • Mofor Emmanuel
    Mofor Emmanuel about 2 years
    making the Ui thread wait can lead to bad UX, why not do that in a different thread