如何将程序延迟一定的毫秒数,或者直到按下某个键?

时间:2011-01-16 13:12:47

标签: c# sleep wait

我需要将程序的执行延迟指定的毫秒数,但也希望用户能够在按下某个键时转义等待。如果没有按下任何键,程序应该等待指定的毫秒数。

我一直在使用Thread.Sleep暂停程序(在我的程序上下文中我觉得没问题,因为UI在主方法执行期间设置为最小化)。

我考虑过做这样的事情:

while(GetAsyncKeyState(System.Windows.Forms.Keys.Escape) == 0 || waitTime > totalWait)
{
    Thread.Sleep(100);
    waitTime += 100;
}

由于Thread.Sleep将等到至少在唤醒线程之前指定的时间,因此在while循环中放大时显然会有很大的不必要的额外延迟。 / p>

是否有某种方法会在指定的时间内睡眠,但只有在条件成立的情况下?或者上面的例子是“正确”的方法,但使用更准确的睡眠方法?如果是这样,我可以使用哪种方法?

提前感谢您的帮助。

编辑----可能的想法......

DateTime timeAtStart = DateTime.Now;
int maxWaitTime = 15000;

while (true)
{
    if (GetAsyncKeyState(System.Windows.Forms.Keys.Escape) != 0)
    {
        break;
    }

    if ((DateTime.Now - timeAtStart).TotalMilliseconds >= maxWaitTime)
    {
        break;
    }
}

这不使用任何类型的计时器,但看起来它可以工作,任何建议?

编辑2:以上对我有用,现在允许我在按下转义时中断等待。我注意到延迟比使用Thread.Sleep更准确!

3 个答案:

答案 0 :(得分:3)

考虑颠倒概念......而不是延迟它一段时间,考虑在某个时间开始执行,或者按下某个键。< / p>

使用tick处理程序启动Windows窗体计时器,它将启动您想要发生的任何事情,将启动它并停止计时器的键事件处理程序。

答案 1 :(得分:2)

第一个示例使用Timer,ManuelResetEvent和Global Keyboard hook:

我没有包含键盘钩子代码,因为它太大了。你可以找到它here

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;

namespace WindowsFormsApplication1
{
    static class Program
    {
        private static System.Threading.Timer _timer;
        private static ManualResetEvent _signal;

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            _signal = new ManualResetEvent(false);

            _timer = new System.Threading.Timer(Timer_Signaled, null, 15000, 0);

            _signal.WaitOne();
            _signal.Reset();

            Application.Run(new Form1());
        }

        private static void Timer_Signaled(object state)
        {
            _signal.Set();
        }
    }
}

当您挂机键盘并按下ESC时,只需调用:_signal.Set()。第一个样本只是为了给你一个想法。

第二个样本:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
    static class Program
    {

        [DllImport("user32.dll")]
        static extern short GetAsyncKeyState(System.Windows.Forms.Keys vKey);

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            int maxWaitTime = 15000;

            int tc = System.Environment.TickCount;

            while (true)
            {
                System.Threading.Thread.Sleep(1000);

                if (System.Environment.TickCount - tc > maxWaitTime)
                {
                    break;
                }

                if (GetAsyncKeyState(Keys.Escape) > 0)
                {
                    break;
                }
            }

            Application.Run(new Form1());
        }
    }
}

编辑:

第一个示例更可靠,因为键盘钩子使用回调来通知哪个键被按下了。第二个样本就像“拉”一样,并且可能不会收集每个按键。

答案 2 :(得分:0)

查看您的代码,我假设您正在使用Windows窗体用于UI。

有很多方法可以解决您的问题,但鉴于框架最容易让我想到的是:

  1. 阻止您的用户界面(即:this.Enabled = false
  2. 设置计时器(即:timer.Tick += ContinueUITimer();
  3. 设置键盘处理程序(即:this.KeyDown += ContinueUIKeyboard
  4. 使用这样的ContinueUI函数:

     void ContinueUIXxx(...) 
     {   
       timer.Tick -= ContinueUITimer;   
       this.KeyDown -= ContinueUIKeyboard;   
       this.Enabled = true;
        ... whatever else in the continuation; 
     }