【问题标题】:How to escape while loop using keyboard input in C#如何在 C# 中使用键盘输入来转义 while 循环
【发布时间】:2019-09-27 09:52:48
【问题描述】:

我在 .Net Framework 8.0 中使用 C#。 我想使用键盘输入来逃避 while 循环。

在下面的 C# 代码中,

1) 如果我删除“MessageBox.Show(State.ToString());”,我就无法逃脱 while 循环。

2) 如果我添加“MessageBox.Show(State.ToString());”,我可以逃避 while 循环。但是,它并不完美。因为看到MessageBox“false”后,必须按“A”回车。然后 Next Step,State 更改为“true”。我可以看到“真实”>“进入!!!”>“当循环被破坏时!!!”消息框。

a) 1) 和 2) 有什么区别。

b) 如何使用键盘输入在 while 循环中转义?很容易。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Windows.Input;

namespace WF_Templete_
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void bt_Start_Click(object sender, EventArgs e)
        {
            while (true)
            {
                bool State = (System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.A) == true);
                // MessageBox.Show(State.ToString());

                if (State)
                {
                    MessageBox.Show("Entered !");
                    break;
                }
            }
            MessageBox.Show("While Loop is Broken !!!");
        }

    }
}

【问题讨论】:

  • 没有.Net-framework 8,只有C# 8。例如框架可能是4.7.1。
  • 请注意,bool State = (System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.A) == true); 可以简化为 bool State = Keyboard.IsKeyDown(Key.A);,因为您已经包含了 System.Windows.Inputbool State = true/false == true 是多余的
  • 这是一个 X-Y 问题。你到底想达到什么目的?
  • 感谢您的 cmets。无论如何,重要的是 while(Keyboard.IsKeyDown(Key.A)) 或 if (Keyboard.IsKeyDown(Key.A)) 不起作用。
  • 但是你想做什么?运行一些后台线程直到按下A 而不阻塞用户界面?正确的答案将取决于您实际尝试做的事情,而不是将您的错误解决方案与任何问题联系在一起......

标签: c# while-loop keyboard


【解决方案1】:

最简单的解决方案是将Application.DoEvents() 添加到循环中。这使您的代码可以处理在紧密循环期间会被忽略的事件。

理想情况下,您希望使用 MVC 或 MVVM 模式在 UI 线程之外运行您的业务逻辑,这将为您提供一个响应式 UI,可以在执行后端处理时与之交互。

            while (true)
            {
                Application.DoEvents();
                bool State = (System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.A) == true);
                // MessageBox.Show(State.ToString());

                if (State)
                {
                    MessageBox.Show("Entered !");
                    break;
                }
            }

【讨论】:

  • 永远不要使用Application.DoEvents()It is evil.
  • 相反,但是你想用什么呢?
  • 默里福克斯克罗夫特)谢谢。 // Matthew Watson) Application.DoEvents() 的缺点是什么?
  • @jaebeomlim Application.DoEvents() 可能会产生各种令人讨厌的副作用,包括意外的重入调用。网络上有很多关于它的讨论,例如stackoverflow.com/questions/5181777/use-of-application-doevents
  • 如果你正在做一个学校项目或者只是一些快速简单的代码(PoC / Demo),没关系。如果您正在运行生产代码,请避免。
【解决方案2】:

从您的 cmets 看来,您似乎希望能够开始等待按下外部 USB 按钮或按下键盘上的取消键。

解决此问题的一种方法是将等待 USB 按钮或取消封装在一个类中,如下所示:

public sealed class UsbButtonWaiter
{
    public UsbButtonWaiter(CancellationToken cancellation)
    {
        _cancellation = cancellation;
    }

    public async Task<bool> WaitForUsbButtonAsync()
    {
        var waitForUsbButton    = Task.Run(this.waitForUsbButton);
        var waitForCancellation = new Task(() => throw new InvalidOperationException(), _cancellation);

        return await Task.WhenAny(waitForUsbButton, waitForCancellation) == waitForUsbButton;
    }

    void waitForUsbButton()  // No idea how your code works for this, so here's a simulation.
    {
        Thread.Sleep(30000); // Simulate it taking 30s for the USB button to be pressed.
    }

    readonly CancellationToken _cancellation;
}

然后您可以使用取消令牌取消等待按下 USB 按钮。

作为如何在表单中使用它的示例,我在这里创建了一个带有单个按钮的表单,名为 button1(向表单添加新按钮时的默认设置)。

当您按下此按钮时,代码将开始等待按下 USB 按钮,或等待用户按下键盘上的 A 键。您可以通过创建一个默认的 Windows 窗体应用程序并将一个默认按钮放到主窗体上来测试此代码(默认情况下将称为 Form1)。

然后将以下代码添加到Form1

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);

        if (_cancellation == null)
            return;

        if (e.KeyCode == Keys.A)
            _cancellation.Cancel();
    }

    async void button1_Click(object sender, EventArgs e)
    {
        if (_cancellation != null) // Already waiting?
            return;

        button1.Enabled = false;
        button1.Text = "Waiting...";

        _cancellation = new CancellationTokenSource();
        UsbButtonWaiter waiter = new UsbButtonWaiter(_cancellation.Token);

        bool wasUsbButtonPressed = await waiter.WaitForUsbButtonAsync();

        if (wasUsbButtonPressed)
            MessageBox.Show("USB button was pressed");
        else
            MessageBox.Show("Cancel key was pressed");

        button1.Enabled = true;
        button1.Text = "button1";
    }

    CancellationTokenSource _cancellation;
}

如果您运行此应用程序并单击button1,其文本将变为Waiting...,并且将被禁用。

然后在您按下A 或 30 秒之前什么都不会发生,此时将显示一个消息框,告诉您是否按下了 USB 按钮或用户取消,并且该按钮将被重新启用。

(请注意,USB 按钮当然不会被真正按下,因为它只是一个模拟,但您可以替换相应的代码。)

【讨论】:

    猜你喜欢
    • 2017-06-20
    • 2016-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-27
    • 1970-01-01
    相关资源
    最近更新 更多