How to asynchronously wait for x seconds and execu

2019-01-14 07:26发布

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"?

7条回答
爷、活的狠高调
2楼-- · 2019-01-14 08:01

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.

查看更多
家丑人穷心不美
3楼-- · 2019-01-14 08:03

your application hangs because you are invoking the 5 second sleep/wait on the main UI thread. put the sleep/wait/whatever action in a separate thread (actually System.Windows.Forms.Timer should do that for you) and when it completes invoke the action that turns some control green. remember to check InvokeRequired. here's a short sample (SetText can be called from another thread, if it is the call will instead be invoked on the main UI thread where the textbox is on):

private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{    
    SetTextCallback d = new SetTextCallback(SetText);
    this.Invoke(d, new object[] { text });
}
else
{
    this.textBox1.Text = text;
}
}

I took the sample from here (well worth a read!).

查看更多
时光不老,我们不散
4楼-- · 2019-01-14 08:04

Have you tried

public static Task Delay(
    int millisecondsDelay
)

You can use like this:

await Task.Deplay(5000);

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

查看更多
地球回转人心会变
5楼-- · 2019-01-14 08:07

(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.

查看更多
放荡不羁爱自由
6楼-- · 2019-01-14 08:10

I think what you are looking for is System.Timers ... I don't think you need to set a CWND timer for what you are trying to do: Have a look at http://msdn.microsoft.com/en-us/library/0tcs6ww8(v=VS.90).aspx for an example. It should do the trick.

查看更多
可以哭但决不认输i
7楼-- · 2019-01-14 08:12

@eFloh in the post marked as answer said:

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

That is not what the docs say.
You are using a System.Windows.Forms.Timer in your example code.
That is a Forms.Timer.
According to the C# docs the Timer events are raised on the UI thread.

This Windows timer is designed for a single-threaded environment where UI threads are used to perform processing. It requires that the user code have a UI message pump available and always operate from the same thread ...

Also see stackoverflow post here

查看更多
登录 后发表回答