Comment puis-je continuer à exécuter mon application console jusqu'à ce qu'une touche soit enfoncée Esc est pressé?)
Je suppose que sa boucle est bouclée. Je n'aime pas ReadKey
car il bloque les opérations et demande une clé, plutôt que de simplement continuer à écouter et d'appuyer sur la touche.
Comment cela peut-il être fait?
Utilisez Console.KeyAvailable
pour que vous appeliez seulement ReadKey
lorsque vous savez que cela ne bloquera pas:
Console.WriteLine("Press ESC to stop");
do {
while (! Console.KeyAvailable) {
// Do something
}
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);
Vous pouvez modifier légèrement votre approche - utilisez Console.ReadKey()
pour arrêter votre application, mais faites votre travail dans un fil d’arrière-plan:
static void Main(string[] args)
{
var myWorker = new MyWorker();
myWorker.DoStuff();
Console.WriteLine("Press any key to stop...");
Console.ReadKey();
}
Dans la fonction myWorker.DoStuff()
, vous invoqueriez une autre fonction sur un thread d'arrière-plan (utiliser Action<>()
ou Func<>()
est un moyen facile de le faire), puis le renvoyer immédiatement.
Le plus court chemin:
Console.WriteLine("Press ESC to stop");
while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape))
{
// do something
}
Console.ReadKey()
est une fonction bloquante, elle arrête l'exécution du programme et attend que l'utilisateur appuie sur une touche. Cependant, grâce à la vérification de Console.KeyAvailable
, la boucle while
n'est pas bloquée, mais elle s'exécute jusqu'au Esc est pressé.
De la malédiction vidéo Construire des applications .NET Console en C # par Jason Roberts à http://www.pluralsight.com
Nous pourrions faire pour avoir plusieurs processus en cours
static void Main(string[] args)
{
Console.CancelKeyPress += (sender, e) =>
{
Console.WriteLine("Exiting...");
Environment.Exit(0);
};
Console.WriteLine("Press ESC to Exit");
var taskKeys = new Task(ReadKeys);
var taskProcessFiles = new Task(ProcessFiles);
taskKeys.Start();
taskProcessFiles.Start();
var tasks = new[] { taskKeys };
Task.WaitAll(tasks);
}
private static void ProcessFiles()
{
var files = Enumerable.Range(1, 100).Select(n => "File" + n + ".txt");
var taskBusy = new Task(BusyIndicator);
taskBusy.Start();
foreach (var file in files)
{
Thread.Sleep(1000);
Console.WriteLine("Procesing file {0}", file);
}
}
private static void BusyIndicator()
{
var busy = new ConsoleBusyIndicator();
busy.UpdateProgress();
}
private static void ReadKeys()
{
ConsoleKeyInfo key = new ConsoleKeyInfo();
while (!Console.KeyAvailable && key.Key != ConsoleKey.Escape)
{
key = Console.ReadKey(true);
switch (key.Key)
{
case ConsoleKey.UpArrow:
Console.WriteLine("UpArrow was pressed");
break;
case ConsoleKey.DownArrow:
Console.WriteLine("DownArrow was pressed");
break;
case ConsoleKey.RightArrow:
Console.WriteLine("RightArrow was pressed");
break;
case ConsoleKey.LeftArrow:
Console.WriteLine("LeftArrow was pressed");
break;
case ConsoleKey.Escape:
break;
default:
if (Console.CapsLock && Console.NumberLock)
{
Console.WriteLine(key.KeyChar);
}
break;
}
}
}
}
internal class ConsoleBusyIndicator
{
int _currentBusySymbol;
public char[] BusySymbols { get; set; }
public ConsoleBusyIndicator()
{
BusySymbols = new[] { '|', '/', '-', '\\' };
}
public void UpdateProgress()
{
while (true)
{
Thread.Sleep(100);
var originalX = Console.CursorLeft;
var originalY = Console.CursorTop;
Console.Write(BusySymbols[_currentBusySymbol]);
_currentBusySymbol++;
if (_currentBusySymbol == BusySymbols.Length)
{
_currentBusySymbol = 0;
}
Console.SetCursorPosition(originalX, originalY);
}
}
Voici une approche pour que vous fassiez quelque chose sur un autre thread et que vous commenciez à écouter la touche appuyée dans un autre thread. Et la console arrêtera son traitement à la fin de votre processus ou lorsque l'utilisateur arrêtera le processus en appuyant sur Esc clé.
class SplitAnalyser
{
public static bool stopProcessor = false;
public static bool Terminate = false;
static void Main(string[] args)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Split Analyser starts");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Press Esc to quit.....");
Thread MainThread = new Thread(new ThreadStart(startProcess));
Thread ConsoleKeyListener = new Thread(new ThreadStart(ListerKeyBoardEvent));
MainThread.Name = "Processor";
ConsoleKeyListener.Name = "KeyListener";
MainThread.Start();
ConsoleKeyListener.Start();
while (true)
{
if (Terminate)
{
Console.WriteLine("Terminating Process...");
MainThread.Abort();
ConsoleKeyListener.Abort();
Thread.Sleep(2000);
Thread.CurrentThread.Abort();
return;
}
if (stopProcessor)
{
Console.WriteLine("Ending Process...");
MainThread.Abort();
ConsoleKeyListener.Abort();
Thread.Sleep(2000);
Thread.CurrentThread.Abort();
return;
}
}
}
public static void ListerKeyBoardEvent()
{
do
{
if (Console.ReadKey(true).Key == ConsoleKey.Escape)
{
Terminate = true;
}
} while (true);
}
public static void startProcess()
{
int i = 0;
while (true)
{
if (!stopProcessor && !Terminate)
{
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("Processing...." + i++);
Thread.Sleep(3000);
}
if(i==10)
stopProcessor = true;
}
}
}
Si vous utilisez Visual Studio, vous pouvez utiliser "Démarrer sans débogage" dans le menu Déboguer.
Il écrira automatiquement "Appuyez sur n’importe quelle touche pour continuer." à la console pour vous à la fin de l'application et il laissera la console ouverte pour vous jusqu'à ce qu'une touche soit enfoncée.
Traiter des cas que certaines des autres réponses ne traitent pas bien:
La plupart des solutions proposées sur cette page impliquent l'interrogation Console.KeyAvailable
ou le blocage sur Console.ReadKey
. S'il est vrai que .NET Console
n'est pas très coopératif ici, vous pouvez utiliser Task.Run
pour passer à un mode d'écoute Async
plus moderne.
Le principal problème à prendre en compte est que, par défaut, votre thread de la console n’est pas configuré pour l’opération Async
- ce qui signifie que, lorsque vous tombez en bas de votre fonction main
, au lieu d’attendre les Async
achèvements, votre AppDoman et processus va se terminer. Une façon appropriée de résoudre ce problème consiste à utiliser AsyncContext de Stephen Cleary pour établir une prise en charge complète de Async
dans votre programme de console à un seul thread. Mais pour des cas plus simples, comme l’attente d’une pression sur une touche, l’installation d’un trampoline complet peut être excessive.
L'exemple ci-dessous concerne un programme de console utilisé dans une sorte de fichier de commandes itératif. Dans ce cas, lorsque le programme est terminé avec son travail, il devrait normalement quitter sans nécessitant une pression sur une touche, puis nous autorisons une touche facultative pour empêcher l'application de quitter. Nous pouvons suspendre le cycle pour examiner des choses, éventuellement reprendre, ou utiliser la pause comme un "point de contrôle" connu pour sortir proprement du fichier de commandes.
static void Main(String[] args)
{
Console.WriteLine("Press any key to prevent exit...");
var tHold = Task.Run(() => Console.ReadKey(true));
// ... do your console app activity ...
if (tHold.IsCompleted)
{
#if false // For the 'hold' state, you can simply halt forever...
Console.WriteLine("Holding.");
Thread.Sleep(Timeout.Infinite);
#else // ...or allow continuing to exit
while (Console.KeyAvailable)
Console.ReadKey(true); // flush/consume any extras
Console.WriteLine("Holding. Press 'Esc' to exit.");
while (Console.ReadKey(true).Key != ConsoleKey.Escape)
;
#endif
}
}
avec le code ci-dessous, vous pouvez écouter en appuyant sur la barre d'espacement, au milieu de l'exécution de la console, mettre en pause jusqu'à ce que vous appuyiez sur une autre touche et écouter EscapeKey pour interrompre la boucle principale.
static ConsoleKeyInfo cki = new ConsoleKeyInfo();
while(true) {
if (WaitOrBreak()) break;
//your main code
}
private static bool WaitOrBreak(){
if (Console.KeyAvailable) cki = Console.ReadKey(true);
if (cki.Key == ConsoleKey.Spacebar)
{
Console.Write("waiting..");
while (Console.KeyAvailable == false)
{
Thread.Sleep(250);Console.Write(".");
}
Console.WriteLine();
Console.ReadKey(true);
cki = new ConsoleKeyInfo();
}
if (cki.Key == ConsoleKey.Escape) return true;
return false;
}