CancelKeyPress - принятие ввода

При написании консольного приложения не так много обработчиков событий, связанных с окном консоли, но я обнаружил, что можно использовать System.Console.CancelKeyPress для прерывания текущего процесса с помощью события.

Предполагая следующую программу:

class Program
{
    static void Main(string[] args)
    {
        Console.ForegroundColor = ConsoleColor.Blue;
        Console.CancelKeyPress += myHandler;
        while (true)
        {
            Console.WriteLine("Hello World!");
            System.Threading.Thread.Sleep(1);
        }
    }



protected static void myHandler(object sender, ConsoleCancelEventArgs args)
    {
        args.Cancel = true;
        Console.WriteLine("  Cancel property: {0}", args.Cancel);
        Console.WriteLine("The read operation will resume...\n");
        Console.ReadLine();
    }
}

Программа печатает "Hello World!" бесконечно на экране. И прерывание работает, я предполагаю, что они разделяют поток, и на долю секунды он переходит в метод Handler, когда вы нажимаете Ctrl + C. Пока он выводит на экран информацию о текущем состоянии свойства cancel, Console.ReadLine () в событии полностью опускается.

Предназначено ли это поведение, чтобы избежать конфликтов блокировки, или есть трюк, как можно прочитать ввод, когда это событие запускается? Например, введите Y, если вы действительно хотите выйти.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
77
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете делать то, что хотите, следующим образом ...

 class Program
{
    private static bool running = true;
    private static bool stop = false;
    static void Main(string[] args)
    {
        Console.ForegroundColor = ConsoleColor.Blue;
        Console.CancelKeyPress += myHandler;
        while (!stop)
        {
                if (running)
                {
                    Console.WriteLine("Hello World!");                      
                } 
            System.Threading.Thread.Sleep(1000);
        }

        Console.WriteLine("Exiting ...");
    }



    protected static void myHandler(object sender, ConsoleCancelEventArgs args)
    {
        args.Cancel = true;
        running = false;
        Console.WriteLine("Do you wish to resume... Y/N \n");
        var resume = Console.ReadLine();

        if (resume == "Y")
        {
            running = true;
        }
        else
        {
            stop = true;
        }
    }
}

Я подозреваю, что обработчик событий работает в другом контексте, чем основной поток окна консоли. Раньше я действительно не использовал события в окнах консоли, но в WinForms графический интерфейс будет работать в собственном потоке контекста.

Ответ принят как подходящий

Обработчик события отмены действительно работает в другом потоке (проверьте это, распечатав идентификатор потока).

Основной поток и вторичный поток, выполняющий событие, не «совместно используют поток», но используют вывод консоли как общий ресурс.

Строка чтения в событии не пропускается. Хотя «основной» поток действительно продолжает писать «Hello World», если вы нажмете клавишу ввода, обработчик событий эффективно прочитает введенные вами данные.

Если вы хотите, чтобы основной поток «приостанавливал» запись в консоль, вам нужно найти механизм для этого.

Вот очень наивная реализация:

    private static bool paused;
    static void Main(string[] args)
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);

        Console.ForegroundColor = ConsoleColor.Blue;
        Console.CancelKeyPress += myHandler;
        while (true)
        {
            if (!paused)
                Console.WriteLine("Hello World!");
            System.Threading.Thread.Sleep(1000);
        }
    }

    protected static void myHandler(object sender, ConsoleCancelEventArgs args)
    {
        paused = true;
        Console.WriteLine("Do you want to exit?");
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        var answer = Console.ReadLine();
        args.Cancel = answer != "y";
        paused = false;
    }

Спасибо за объяснение, которое действительно прояснило, почему это так.

mayen 13.08.2018 14:20

Другие вопросы по теме