Wie kann ich meine Konsolenanwendung so lange ausführen, bis eine Taste gedrückt wird? Esc wird gedrückt?)
Ich gehe davon aus, dass es um eine while-Schleife gewickelt ist. Ich mag ReadKey
nicht, da es die Bedienung blockiert und nach einer Taste fragt, anstatt einfach fortzufahren und auf den Tastendruck zu warten.
Wie geht das?
Verwenden Sie Console.KeyAvailable
, damit Sie nur ReadKey
aufrufen, wenn Sie wissen, dass es nicht blockiert:
Console.WriteLine("Press ESC to stop");
do {
while (! Console.KeyAvailable) {
// Do something
}
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);
Sie können Ihre Vorgehensweise leicht ändern - verwenden Sie Console.ReadKey()
, um Ihre App zu stoppen, erledigen Sie jedoch Ihre Arbeit in einem Hintergrund-Thread:
static void Main(string[] args)
{
var myWorker = new MyWorker();
myWorker.DoStuff();
Console.WriteLine("Press any key to stop...");
Console.ReadKey();
}
In der Funktion myWorker.DoStuff()
würden Sie dann eine andere Funktion in einem Hintergrundthread aufrufen (mithilfe von Action<>()
oder Func<>()
ist dies eine einfache Möglichkeit), und sofort zurückkehren.
Der kürzeste Weg:
Console.WriteLine("Press ESC to stop");
while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape))
{
// do something
}
Console.ReadKey()
ist eine blockierende Funktion, die die Ausführung des Programms stoppt und auf einen Tastendruck wartet. Dank der Überprüfung von Console.KeyAvailable
wird die while
-Schleife jedoch nicht blockiert, sondern ausgeführt, bis die Esc wird gedrückt.
Aus dem Video-Fluch Erstellen von .NET-Konsolenanwendungen in C # von Jason Roberts unter http://www.pluralsight.com
Wir könnten folgendes tun, um mehrere Prozesse auszuführen
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);
}
}
Hier ist ein Ansatz für Sie, um etwas in einem anderen Thread zu tun und die in einem anderen Thread gedrückte Taste anzuhören. Die Konsole stoppt die Verarbeitung, wenn der eigentliche Vorgang beendet wird oder der Benutzer den Vorgang durch Drücken von beendet Esc Schlüssel.
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;
}
}
}
Wenn Sie Visual Studio verwenden, können Sie "Start ohne Debuggen" im Debug-Menü verwenden.
Es wird automatisch geschrieben "Drücken Sie eine beliebige Taste, um fortzufahren." Wenn Sie die Anwendung abgeschlossen haben, wird die Konsole für Sie geöffnet, bis die Taste geöffnet ist.
Fälle behandeln, bei denen einige der anderen Antworten nicht gut funktionieren:
Viele der Lösungen auf dieser Seite beinhalten das Abfragen von Console.KeyAvailable
oder das Blockieren von Console.ReadKey
. Es stimmt zwar, dass .NET Console
hier nicht sehr kooperativ ist, aber Sie können Task.Run
verwenden, um zu einem moderneren Async
-Hörmodus zu gelangen.
Das Hauptproblem, das Sie beachten sollten, ist, dass Ihr Konsolenthread standardmäßig nicht für die Async
-Operation eingerichtet ist. Dies bedeutet, dass Sie, wenn Sie aus der main
-Funktion fallen, nicht auf Async
-Vervollständigungen, Ihr AppDoman und Prozess wird enden. Um dies zu beheben, sollten Sie Stephen Clearys AsyncContext verwenden, um die vollständige Async
-Unterstützung in Ihrem Singlethread-Konsolenprogramm herzustellen. In einfacheren Fällen, wie z. B. Warten auf einen Tastendruck, kann der Einbau eines vollen Trampolins zu viel sein.
Das folgende Beispiel würde für ein Konsolenprogramm gelten, das in einer Art iterativer Batchdatei verwendet wird. Wenn das Programm mit seiner Arbeit fertig ist, sollte es normalerweise beenden, ohne dass einen Tastendruck erfordert, und dann wird durch einen optionalen Tastendruck verhindert, dass die App beendet wird. Wir können den Zyklus anhalten, um Dinge zu untersuchen, möglicherweise fortsetzen, oder die Pause als bekannten "Kontrollpunkt" verwenden, an dem die Batch-Datei sauber ausgebrochen wird.
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
}
}
mit dem folgenden Code können Sie SpaceBar hören, während Sie die Konsole ausführen, bis eine andere Taste gedrückt wird, und auf EscapeKey warten, um die Hauptschleife zu unterbrechen
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;
}