【问题标题】:Wait for Keypress (or) N Seconds to Expire等待按键(或)N 秒过期
【发布时间】:2012-07-31 21:38:12
【问题描述】:

假设我的控制台程序执行多个冗长的任务。在这些任务之间,我希望它暂停 - 几秒钟 直到按下任何键。 (以先到者为准。)

这些标准本身很容易检查,但当我尝试将它们结合起来时它们拒绝相处:要么计时机制在 ReadKey 启动前暂停几秒钟,要么 Readkey 阻止完全穿线直到满意。我怎样才能同时满足这两个条件?

【问题讨论】:

  • 有什么可用的例子吗?这听起来好像你只能通知主线程这已经完成,然后在那里等待直到你可以继续,跟踪任何计时器并在键盘按下时停止它,但没有示例就无法详细说明

标签: c# timer sleep keypress


【解决方案1】:

从 ikh 的回答开始,我想和我一起倒计时

        var original = DateTime.Now;
        var newTime = original;

        var waitTime = 10;
        var remainingWaitTime = waitTime;
        var lastWaitTime = waitTime.ToString();
        var keyRead = false;
        Console.Write("Waiting for key press or expiring in " + waitTime);
        do
        {
            keyRead = Console.KeyAvailable;
            if (!keyRead)
            {
                newTime = DateTime.Now;
                remainingWaitTime = waitTime - (int) (newTime - original).TotalSeconds;
                var newWaitTime = remainingWaitTime.ToString();
                if (newWaitTime != lastWaitTime)
                {
                    var backSpaces = new string('\b', lastWaitTime.Length);
                    var spaces = new string(' ', lastWaitTime.Length);
                    Console.Write(backSpaces + spaces + backSpaces);
                    lastWaitTime = newWaitTime;
                    Console.Write(lastWaitTime);
                    Thread.Sleep(25);
                }
            }
        } while (remainingWaitTime > 0 && !keyRead);

【讨论】:

    【解决方案2】:

    这样的?

    bool IsPaused;
    bool IsKeyPaused;
    
    void Pause(){}
    void UnPause(){}
    
    void KeyDown(){
        if(!IsPaused)
        {
            IsPaused = true;
            IsKeyPaused = true;
            Pause();
        }
    }
    void KeyUp(){
        if(IsKeyPaused)
        {
            IsPaused = false;
            IsKeyPaused = false;
            UnPause();
        }
    }
    void TimerPause(){
        if(!IsPaused)
        {
            IsPaused = true;
            Pause();
        }
    }
    void TimerEnd(){
         UnPause();
    }
    

    【讨论】:

      【解决方案3】:

      做到这一点的一种方法是完全不使用计时器。创建一个循环,使线程休眠 25 毫秒,然后检查是否已通过Console.KeyAvailable(非阻塞)按下某个键,或者直到DateTime.Now() 和循环开始时间之间的时间已超过超时时间。

      【讨论】:

      • 如果在程序运行时更改系统时间,这将无法正常工作,是吗?
      【解决方案4】:

      在 C# 4.0 中执行此操作的一种方法:

      Task.Factory.StartNew(() => Console.ReadKey()).Wait(TimeSpan.FromSeconds(5.0));
      

      【讨论】:

      • 如果您需要知道来源,那么只需将Wait 调用的结果保存到布尔变量即可。如果超时,则返回 false,否则返回 true(表示有可用的密钥)。
      • 我应该补充一点,您可能应该只将这种方法用于没有很多步骤的短期控制台应用程序,因为每次采用“超时”路径时,都会有一个僵尸线程坐在等待按键。不要在 10,000 计数循环内尝试此操作!
      • @Wayne 这是一个很好的观点,我没有想到这一点。 (而且我确实计划多次使用它)我应该采取任何措施来防止它们堆积吗?
      【解决方案5】:

      启动两个线程。一个监听按键,另一个等待一段时间。让主线程等待,除非任何一个完成。然后继续并忽略其他线程响应。 :)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多