Reputation: 11
I am using C# in the .Net Framework 8.0. I want to escape while loop using Keyboard input.
At below C# code,
1) If I remove " MessageBox.Show(State.ToString()); ", I can't escape the while loop.
2) If I add "MessageBox.Show(State.ToString());", I can escape the while loop. But, it's not perfect. Because after I see the MessageBox " false ", I must press "A" and Enter. Then Next Step, State is changed to "true". And I can see "true" > " Entered !!! " > "While Loop is Broken !!!" MessageBox.
a) What is the difference 1) and 2).
b) How can I escape while loop using keyboard input? Easily.
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 !!!");
}
}
}
Upvotes: 1
Views: 1411
Reputation: 109567
From your comments, it looks like you want to be able to start waiting for an external USB button press, or for a cancellation key on the keyboard to be pressed.
One way to approach this is to encapsulate the waiting for USB button or cancellation in a class like so:
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;
}
Then you can use a cancellation token to cancel waiting for the USB button press.
As an example of how to use this in a form, here I have created a form with a single button called button1
(the default when you add a new button to a form).
When you press this button, the code will start waiting for a USB button press, or for the user to press the A
key on the keyboard. You can test this code by creating a default Windows Forms app and dropping a default button onto the main form (which will be called Form1
by default).
Then add the following code to 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;
}
If you run this application and click button1
, its text will change to Waiting...
, and it will become disabled.
Then nothing will happen until either you press A
or 30s elapses, whereupon a message box will be displayed telling you if the USB button was pressed or the user cancelled, and the button will be re-enabled.
(Note that, of course, the USB button is never really pressed since it is just a simulation, but you can substitute the appropriate code.)
Upvotes: 0
Reputation: 13755
The simplest solution is to add in Application.DoEvents() in to the loop. This allows your code to process events that would otherwise be ignored during a tight loop.
Ideally you would want to run your business logic outside of the UI thread using a MVC or MVVM pattern, which would then leave you with a responsive UI that can be interacted with whilst back end processing is performed.
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;
}
}
Upvotes: 1