2012-08-02 8 views
8

Supponiamo che il mio programma di console esegua più attività lunghe. Tra queste attività, mi piacerebbe che si fermasse - per qualche secondo, o fino a quando non viene premuto un tasto. (Quello che viene prima.)Attesa per la pressione dei tasti (o) N secondi per la scadenza

Tali criteri sono facili da controllare da soli, ma si rifiutano di andare d'accordo quando provo loro combinazione: O il meccanismo di temporizzazione si interrompe per alcuni secondi prima ReadKey inizia, o blocchi ReadKey fuori il filo interamente fino a quando soddisfatto. Come posso soddisfare entrambe le condizioni?

+3

http://stackoverflow.com/questions/57615/how-to-add-a-timeout-to-console- readline – dugas

+0

Qualche esempio disponibile? Sembra come se fosse possibile notificare solo il thread principale, quindi attendere lì finché non si può continuare, tenere traccia di qualsiasi timer e fermarlo se la tastiera è premuta, ma non può elaborare senza esempio –

risposta

15

Un modo per fare questo in C# 4.0:

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

Se è necessario conoscere il sorgente, quindi basta salvare il risultato della chiamata 'Wait' a una variabile bool. Se è scaduto, restituirà false, altrimenti restituirà true (ovvero è disponibile una chiave). – SPFiredrake

+3

Avrei dovuto aggiungere che probabilmente dovresti utilizzare questo approccio solo per le app di console di breve durata che non hanno molti passaggi, poiché ogni volta che viene eseguito il percorso di "timeout", ci sarà un thread di zombie in attesa di una chiave stampa. Non provarlo all'interno di un ciclo di conteggio da 10.000! – lesscode

+0

@Wayne Questo è un buon punto, non ci avevo pensato. (E ho intenzione di usarlo molte volte) Devo fare qualche passo per impedire che si accumulino? – 4444

0

Avvia due thread. Si ascolta keypress e altre attese per un po 'di tempo. Fai in modo che il thread principale attenda a meno che qualcuno non lo faccia. Quindi procedere e ignorare la risposta di altri thread. :)

3

Un modo per farlo è senza timer a tutti. Crea un ciclo che interrompe il thread per 25 millisecondi, quindi controlla se un tasto è stato premuto tramite Console.KeyAvailable (che non è bloccato), o fino a quando l'intervallo tra DateTime.Now() e l'ora di inizio del ciclo ha superato il timeout .

+0

Questo non funzionerà correttamente se l'ora del sistema viene modificata mentre il programma è in esecuzione, sara? –

0

Qualcosa di simile?

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(); 
} 
2

estende dalla risposta di Ikh volevo un conto alla rovescia con la mia

 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);