wake-up-neo.com

Warten Sie in der .NET-Konsolen-App auf Tastendruck

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?

194

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);
289
Jeff Sternal

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.

71
slugster

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.

49
Yuliia Ashomok

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);
        }
    }
16
alhpe

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;

        }
    }

}
12
waheed

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.

3
LVBen

Fälle behandeln, bei denen einige der anderen Antworten nicht gut funktionieren:

  • Responsive: direkte Ausführung des Code für die Tastendruckverarbeitung; vermeidet die Launen von Abfragen oder Blockierungen von Verzögerungen
  • Optionalität: globaler Tastendruck ist Opt-in; Andernfalls sollte die App normal beendet werden
  • Trennung von Anliegen: weniger invasiver Hörcode; arbeitet unabhängig vom normalen Code der Konsolen-App.

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
    }
}
1
Glenn Slayden

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;
    }
0
Iman Abidi