CancelKeyPress-接受输入

时间:2018-08-13 11:31:24

标签: c# events .net-core

编写控制台应用程序时,与控制台窗口有关的EventHandler很少,但是我发现可以使用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!”。无限地出现在屏幕上而且中断的工作原理是,我假设它们共享一个线程,并在您按下Ctrl + C的那一秒钟之内进入了Handler方法。当它在屏幕上打印出有关cancel属性当前状态的信息时,事件中的Console.ReadLine()被完全省略。

此预期的行为是为了避免阻止冲突,还是有一个技巧可以引发此事件时如何读取输入?如果您确实要退出,请像键入Y。

2 个答案:

答案 0 :(得分:1)

您可以按照以下步骤做您想做的事情...

 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中,GUI将在其自己的上下文线程上运行。

答案 1 :(得分:1)

cancel事件处理程序确实在另一个线程上运行(通过打印出线程ID进行验证)。

运行该事件的主线程和辅助线程不会“共享线程”,但是会使用控制台输出作为共享资源。

事件中的readline不会被忽略。尽管“主”线程确实确实继续编写“ Hello World”,但是如果您按Enter键,事件处理程序将有效地读取您输入的输入。

如果希望主线程“暂停”写入控制台,则必须找到一种机制来做到这一点。

这是一个非常幼稚的实现:

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