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

前端 未结 8 853
深忆病人
深忆病人 2020-12-03 03:03

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 fo

相关标签:
8条回答
  • 2020-12-03 03:18

    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.

    0 讨论(0)
  • 2020-12-03 03:22

    @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

    0 讨论(0)
  • 2020-12-03 03:26

    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]

    0 讨论(0)
  • 2020-12-03 03:32

    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

    0 讨论(0)
  • 2020-12-03 03:35

    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!).

    0 讨论(0)
  • 2020-12-03 03:36

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

    0 讨论(0)
提交回复
热议问题