Escape button to close Windows Forms form in C# - c#

I have tried the following:
private void Form1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
if ((Keys) e.KeyValue == Keys.Escape)
this.Close();
}
But it doesn't work.
Then I tried this:
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.KeyCode == Keys.Escape)
this.Close();
}
And still nothing's working.
The KeyPreview on my Windows Forms form properties is set to true... What am I doing wrong?

This will always work, regardless of proper event handler assignment, KeyPreview, CancelButton, etc:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (keyData == Keys.Escape) {
this.Close();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}

You should just be able to set the Form's CancelButton property to your Cancel button and then you won't need any code.

Assuming that you have a "Cancel" button, setting the form's CancelButton property (either in the designer or in code) should take care of this automatically. Just place the code to close in the Click event of the button.

The accepted answer indeed is correct, and I've used that approach several times. Suddenly, it would not work anymore, so I found it strange. Mostly because my breakpoint would not be hit for ESC key, but it would hit for other keys.
After debugging I found out that one of the controls from my form was overriding ProcessCmdKey method, with this code:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
// ...
if (keyData == (Keys.Escape))
{
Close();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
... and this was preventing my form from getting the ESC key (notice the return true). So make sure that no child controls are taking over your input.

You set KeyPreview to true in your form options and then you add the Keypress event to it. In your keypress event you type the following:
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 27)
{
Close();
}
}
key.Char == 27 is the value of escape in ASCII code.

You need add this to event "KeyUp".
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.Escape)
{
this.Close();
}
}

You can also Trigger some other form.
E.g. trigger a Cancel-Button if you edit the Form CancelButton property and set the button Cancel.
In the code you treath the Cancel Button as follows to close the form:
private void btnCancel_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Abort;
}

By Escape button do you mean the Escape key? Judging by your code I think that's what you want. You could also try Application.Exit(), but Close should work. Do you have a worker thread? If a non-background thread is running this could keep the application open.

Related

Why is my C# WinForms window not closing in response to Enter key?

I have a basic WinForms project where the user clicks a button. This opens another form as follows:
form2 myForm2 = new form2();
myForm2.ShowDialog();
Inside this new form, there are four buttons which represent values. The user presses the SPACE key to jump between buttons and the ENTER key to select one. When the user presses ENTER on a button I want the form to close. For this is I use 'this.Close()'. This works for absolutely fine with every key other than ENTER. I am using visual studio so I have inserted a break point and stepped over the code. The ENTER key is detected successully and I can step over the code 'this.Close()' but the window never closes. My code is a followed:
private void button1_KeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Space)
{
// Change colour of the button you are on. This works fine.
}
else if (e.KeyCode == Keys.Enter)
{
this.Close();
// This will close the form with all keys other than the Enter key. Yet the enter key is
// successfully detected and the program enters this else if statement.
}
}
Any help is much appreciated, Thanks.
I'd override ProcessCmdKey() and make the space key act like the tab key to select the next control. Then just handle each the click event of each button like normal. The click handler for the buttons will fire when the user presses enter:
public partial class form2 : Form
{
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
Button btn = this.ActiveControl as Button;
if (btn != null)
{
if (keyData == Keys.Space)
{
// possibly do something else with "btn"?...
this.SelectNextControl(btn, true, true, true, true);
return true; // suppress default handling of space
}
}
return base.ProcessCmdKey(ref msg, keyData);
}
private void button1_Click(object sender, EventArgs e)
{
// possibly set some value?
Console.WriteLine("button1");
this.DialogResult = DialogResult.OK;
}
private void button2_Click(object sender, EventArgs e)
{
// possibly set some value?
Console.WriteLine("button2");
this.DialogResult = DialogResult.OK;
}
private void button3_Click(object sender, EventArgs e)
{
// possibly set some value?
Console.WriteLine("button3");
this.DialogResult = DialogResult.OK;
}
private void button4_Click(object sender, EventArgs e)
{
// possibly set some value?
Console.WriteLine("button4");
this.DialogResult = DialogResult.OK;
}
}
An alternative approach would be to also trap the enter key in ProcessCmdKey() like this:
public partial class Form2 : Form
{
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
Button btn = this.ActiveControl as Button;
if (btn != null)
{
if (keyData == Keys.Space)
{
Console.WriteLine("Space -> Tab");
// possibly do something else with "btn"?...
this.SelectNextControl(btn, true, true, true, true);
return true; // suppress default handling of space
}
else if (keyData == Keys.Enter)
{
Console.WriteLine("Enter in ProcessCmdKey() for " + btn.Name);
// possibly do something else with "btn"?...
this.Close();
// < or >
this.DialogResult = DialogResult.OK;
return true;
}
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
Looking into signature of the handler (object sender, PreviewKeyDownEventArgs e) apparently OP is already handling PreviewKeyDown event.
I reproduced and solved the problem.
The behavior is different when you open a Form using Show or ShowDialog. Everything works as expected with Show, but when using ShowDialog, to close the form in PreviewKeyDown, you need to use one of the following options:
private void button1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
e.IsInputKey = true;
this.Close();
// OR
// if (e.KeyData == Keys.Enter)
// this.BeginInvoke(new Action(() => this.Close()));
// OR first hide, then close, without calling BeginInvoke
// this.Hide();
// this.Close();
}
There should be something about model message loop. I didn't traced in details, but you may find the following links useful:
LocalModalMessageLoop in Application
CheckCloseDialog in Form
WMClose in Form
Just as a side note: If the Enter should be handled at form level, then setting AcceptButton of the form or overriding ProcessKeyDown or ProcessDialogKey of the form is the way to go.

C# Windows Forms Applications Hotkey - KeyDown event not working

I read a lot of questions about making a hotkey for a Windows Forms Applications and tried the code a lot people said it was working, but for me, somehow not.
Code:
void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
timer1.Stop();
e.SuppressKeyPress = true;
}
}
If you want to create global hotkeys manager for your form to be available for all controls in that form, you need to override the Form.ProcessCmdKey() method that catch all keys for all controls, instead of using the form key down event that works only when the background is focused and which can only happens when ActiveControl is null:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
switch ( keyData )
{
case Keys.Control | Keys.S:
timer1.Stop();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
Thus you can catch any key combination you need and return true if processed.

How do I bind a keyboard key to a label

I am trying to bind a keyboard button (preferably "ESC") to stop the code that is running inside the method. But the thing is, it only works with actual buttons, is there anyway to bypass this so it works when pressing labels aswell?
private void label1_Click(object sender, EventArgs e)
{
if (e.Control && e.KeyCode.ToString() == "ESC")
{
MessageBox.Show("This does now work");
}
}
I've read somewhere that it is possible its just that the Visual Studio GUi doesnt provide it, but you can do it with code somehow, is this true?
I am not sure what you are trying to do. The following will get the Escape key when it is pressed when the focus is in the form regardless of what control has the focus. Just add this to the form (the code of course).
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Escape))
{
MessageBox.Show("This works");
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}

Tab will not fire keydown or keypress event

I am working in a webform and have a form with a tab bar on it. Each tab has multiple text boxes in it. I have the tab indexes incremented, starting with 1 for each tab. I want to tab from tab to tab if the user hits the end of the form and hits tab.
I used the leave method and changed the tabs for my tab control the only problem is if I didn't hit tab and say I click to another control on that tab it will still shoot over to the new tab.
I figure a way to solve this would be to listen for the tab key press and if the key press is tab on leave then change the form to the other tab, I just can't seem to get it to work though. I have tried with keypress and keydown but neither will pick up that tab as a key. If I was to say click or hit start typing it will trigger the events but tab will not.
Any suggestions?
I have tried these and none of these event would even trigger.
private void afsiTxtDaysForTempOEpriceOverrides_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 11)
{
afsiTxtDaysForTempOEpriceOverrides_Leave(sender, e);
}
}
private void afsiTxtDaysForTempOEpriceOverrides_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == "11")
{
afsiTxtDaysForTempOEpriceOverrides_Leave(sender, e);
}
}
private void afsiChkSalesBaseCostUpdate_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 11)
{
afsiChkSalesBaseCostUpdate_Leave(sender, e);
}
}
private void afsiChkSalesBaseCostUpdate_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == 11)
{
afsiChkSalesBaseCostUpdate_Leave(sender, e);
}
}
EDIT: Found out that the page is using UltraWinTabControl from Infragistics so maybe this is causing some issues with the tabbing.
I ended up needing to override ProcessCmdKey now I face a new problem that is kind of related but not particular to this so I will add it as a comment if I get my answer.
private bool isTab = false;
private bool isShiftTab = false;
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Tab)
{
isTab = true;
ShiftTab.Append("Tab");
}
else
{
isTab = false;
}
return base.ProcessCmdKey(ref msg, keyData);
}
You will need to have the MultiLine property set to true, and AcceptsTab also set to true.
Or use e.KeyCode instead or e.KeyData, it worked for me
if (e.KeyCode == Keys.Tab | e.KeyData == Keys.Enter)

Why does the PreviewKeyDown event get called a second time when IsInputKey is set true?

VS2010 C# .Net 4.1
I am working on a form that the user must select or enter initial data in a ComboBox. Using the code below, which took some time to deduce, I enable the Edit button when the user hits the Tab key if the data is correct, otherwise the button is disabled it moves to the next button.
This code works, but a side effect is that the PreviewKeyDown event reoccurs when I set IsInputKey to true. This calls validation twice. The KeyDown event is only called once, and the IsInputKey is false again on the second call so I do need to check validation again.
I'd like to understand why and possibly avoid it.
private void comboBox1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) {
if (e.KeyData == Keys.Tab) {
if (ValidationRoutine()) {
e.IsInputKey = true; //If Validated, signals KeyDown to examine this key
} //Side effect - This event is called twice when IsInputKey is set to true
}
}
private void comboBox1_KeyDown(object sender, KeyEventArgs e) {
if (e.KeyData == Keys.Tab) {
e.SuppressKeyPress = true; //Stops further processing of the TAB key
btnEdit.Enabled = true;
btnEdit.Focus();
}
}
The why? is hard to answer, Winforms just does. First from the message loop, again from the control's message dispatcher. The event was really meant as an alternative way to implement the protected IsInputKey() method without having to override the control class. Bit of a hack, I always override and never used the event.
The better mouse trap is to override ProcessCmdKey() instead. Like this:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (this.ActiveControl == comboBox1 && keyData == Keys.Tab) {
if (ValidationRoutine()) {
btnEdit.Enabled = true;
btnEdit.Focus();
return true;
}
}
return base.ProcessCmdKey(ref msg, keyData);
}

Categories