C# How to escape form's Accept Button from getting triggered - c#

I have a Windows Form, with a ListView and a TextBox placed right on top of it. Also there is a button named 'Submit' on the Form with AcceptButton set to true.
Now, my requirement is that, whenever I load the form and hit Enter, Submit button gets triggered, which is fine. But, when I select the TextBox and type something in it and then hit Enter, the focus should come to the ListView , but not the AcceptButton
How can I achieve this?

You can set the AcceptButton based on the active control, or as a better option, handle ProcessDialogKey yourself. This is the method which contains the logic for AcceptButton.
So you can override it, for example:
protected override bool ProcessDialogKey(Keys keyData)
{
if (keyData == Keys.Enter)
{
if (this.ActiveControl == this.textBox1)
{
MessageBox.Show("Enter on TextBox1 handled.");
return true; //Prevent further processing
}
}
return base.ProcessDialogKey(keyData);
}

Related

The Enter Key does not close a Form if the Focus is on a Button that is not the AcceptButton

I have a modal Form with three Buttons, A B and C.
In addition, I have two Buttons: OK and Cancel. The OK Button's DialogResult property is set to DialogResult.OK and the Cancel Button DialogResult.Cancel.
The Form's AcceptButton and CancelButton properties are set to these Buttons.
Currently, the Form is closed when I press the ESC key but if I click the ENTER key when one of the other Buttons (A,B,C) is the Active Control, the Form is not closed. How can I overcome this?
I have two options:
Enter will always close the form (select the focused button and then close it),
The first Enter key press will select the focused button and a second ENTER press will close the Form. The problem is that maybe Button A was selected but the user can go over Button B or C using the arrow keys.
I can't set a DialogResult.OK to the other Buttons, because - in that case - a normal click will also close the Form and I have no way to detect if the event was called because of a Click event or the ENTER key...
If you want to activate the Default button - the Button that is set as the Form's AcceptButton - when another Button has the Focus, but not another Control, as a TextBox, that may want to accept the Enter key, you can override ProcessCmdKey (since pressing the Enter key doesn't raise the KeyDown event and the Click event is raised before the KeyUp event), verify whether the ActiveControl is of type Button (or other type of Controls you want to behave the same way) and set the ActiveControl to your AcceptButton.
The Enter key is transferred to the AcceptButton and the Dialog is Closed, returning DialogResult.OK (since you have already set the Button's DialogResult value):
Note: this assuming that the Container Control is the same.
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Enter) {
if (ActiveControl.GetType() == typeof(Button) &&
ActiveControl != AcceptButton) {
ActiveControl = AcceptButton as Button;
}
}
return base.ProcessCmdKey(ref msg, keyData);
}
In case you just want to change the ActiveControl, setting the Focus to the AcceptButton - so the User needs to press the Enter key twice to confirm, return true after you have changed the ActiveControl, to signal that the input has been handled:
// [...]
if (keyData == Keys.Enter) {
if (...) {
ActiveControl = AcceptButton as Button;
return true;
}
}
return base.ProcessCmdKey(ref msg, keyData);

Different AcceptButton for different Panels on Form

I have a form with a Search button & Submit button, they are sitting on different panels but in the same form. I want to use the AcceptButton property of the Form with both buttons based on criteria.
The user will search for a ticket using the box on the right panel, which will populate the datagridview below. The user will then select a row, which I have bound to the text boxes on the left panel. The New Asset textbox is blank, so the user will have to populate that before hitting submit.
Is there anyway to bind the AcceptButton Property to the search textbox (right panel) if the new asset number textbox is null and then bind the property to the submit button (left panel) after the user populates the text box.
Sorry if this is hard to understand. I am still learning c# and all of the things I can do with it.
Note: While I also believe the UI design in the question case can be improved, but in general having multiple default button for different parts of a page can be considered as a normal requirement, like html form elements which
are supposed to run their submit button code if you press enter on any
form element, while you can have multiple form on a single
page.
What you need to do is overriding ProcessDialogKey and check if the first panel contains focus then perform click of the first button and if the second panel contains focus then perform click of the second button:
protected override bool ProcessDialogKey(Keys keyData)
{
if (keyData == Keys.Enter)
{
if (panel1.ContainsFocus)
{
button1.PerformClick();
return true;
}
if (panel2.ContainsFocus)
{
button2.PerformClick();
return true;
}
}
return base.ProcessDialogKey(keyData);
}
You also have the option of handling Enter event of controls and assign AcceptButton of the form based on the focused control. But above/below
solutions are more general with less code.
Note - Creating a Panel class having AcceptButton property
Apart from above solution, as a more reusable solution for those who wants to handle such cases by less code, you can use such panel class having AcceptButton property:
using System.Windows.Forms;
public class MyPanel : Panel
{
public Button AcceptButton { get; set; }
protected override bool ProcessDialogKey(Keys keyData)
{
if (keyData == Keys.Enter)
{
AcceptButton?.PerformClick();
return true;
}
return base.ProcessDialogKey(keyData);
}
}

Prevent button from being focused by arrow key click

How can I prevent that if the user presses one of the arrow keys, a button on the form is focused?
I am programming a small game, so this would prevent the user from being able to move. Sorry for the vague explanation.
EDIT:
The player is a PictureBox with a graphic in it that is moved by:
private async void Form1_KeyDown(object sender, KeyEventArgs e)
In your Form.cs override the ProcessCmdKey like this:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (!msg.HWnd.Equals(Handle) &&
(keyData == Keys.Left || keyData == Keys.Right ||
keyData == Keys.Up || keyData == Keys.Down))
return true;
return base.ProcessCmdKey(ref msg, keyData);
}
A way to handle this scenario is to set form.KeyPreview = true (see MSDN) and then handle the keys in KeyPress / KeyDown event handlers:
Quoting MSDN for KeyPress Event:
To handle keyboard events only at the form level and not enable other controls to receive keyboard events, set the
KeyPressEventArgs.Handled property in your form's KeyPress
event-handling method to true.
Test for arrow in your keysEvent, manage them the way you need and set Handled=true to avoid default behavior (move focus to next control)
What works for me is to set the button property "TabStop" to false and you can also play with the TabIndex property of the controls on the form to technically set what will be focused when the form loads.
TabStop - sets if pressing TAB can set/give focus to the control and when pressing the TAB key it will increment through the controls on the form according to the -
TabIndex - which dictates which control will get focus next.
So if Button A has tabIndex 1 and Button B has tabIndex 2 and button C has tabIndex 3, but Button B has tabStop = false, then pressing TAB will go from button A to Button C, it will skip Button B.
-Keep in mind that not all controls seem to have a "TabStop" property, I have noticed that textbox, button and datagridview does have the property, but stuff like labels and groupbox and picturebox does not have TabStop, only TabIndex.

Validating Data In A WinForm

I have created a dialog box in my WinForms application. This has many text boxes and ok/cancel buttons. When the user clicks ok, I only want the dialog box to close if all entries are valid. I can see how to do this with the "Validating" events for each control separately. That is fine. But these only seem to fire when a control loses focus. However, empty text boxes in my dialog are also invalid input which means the user may never have focused on that control. I would prefer to just validate all controls on clicking OK.
I can't work out how to do this though. Overriding the onclick of the OK button doesn't seem to have an option for stopping the window from closing. The Form IsClosing event does by setting Cancel = true. But this doesn't seem to be able to distinguish between whether the OK or Cancel button is clicked. Obviously if the cancel button is clicked I don't care about validation and want to allow the form to close regardless.
What is the best approach for doing this?]
Update:
I already had CausesValidation set to true on both my form and ok button but my validation event does not get fired when I click the ok button. I mention this as it was suggested as a solution below.
Please select the form > Set the property CausesValidation to true
Select OK button and again set property CausesValidation to true
and then it will take care of all the validations.
Important points:
1) You must mention e.Cancel=true in all the validating eventhandlers
2) If your buttons are in panels then you must set panels (or any parent control's) CausesValidation property to true
Edit:
3) Validate fires just before loss of focus. While pressing Enter will
cause the default button to Click, it doesn't move the focus to that
button, hence no validation event will be fired if you have set forms AcceptButton Property to OK button
First make sure to cancel the validation when any of the textboxes have validation errors. For example:
private void nameTextBox_Validating(object sender, CancelEventArgs e) {
if (nameTextBox.Text.Length == 0)
{
e.Cancel = true;
return;
}
}
Now add the following code to the beginning of the ok button action:
if (!ValidateChildren())
return;
This will trigger the validation event for all controls on the form,
You can also use this simple code. just introducing a simple Boolean variable named hasError can do the job.
public partial class Form1 : Form
{
private bool hasError;
public Form1()
{
InitializeComponent();
}
private void OkBtn_Click(object sender, EventArgs e)
{
errorProvider1.Clear(); hasError=false;
if (ValidateTxt.Text.Length == 0)
{
errorProvider1.SetError(ValidateTxt, "must have a value");
hasError=true;
}
if (!hasError)
{
//Do what you want to do and close your application
Close();
}
}
private void CancelBtn_Click(object sender, EventArgs e)
{
Close();
}
}

C#: Trouble with Form.AcceptButton

I have a form with an button which is set as the AcceptButton of the form. The form has several other controls. Now when I press Enter on other controls the form gets closed because of the accept button on the form. Same goes for CancelButton. How do I handle this. I tried hooking on to keypress keydown event of the form and controls. None works. Any work around for this?
Thanks a ton,
Datte
That is how the AcceptButton property works. It specifies the button that is automatically clicked whenever you press <Enter>.
If you don't want this behaviour, don't set it as the AcceptButton. There is no other reason to do it.
Not exactly sure about how you expect your form to function, but you could do something like the following to have a little more control over things:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Enter)
{
// do something
}
if (keyData == Keys.Escape)
{
// do something else
}
return base.ProcessCmdKey(ref msg, keyData);
}
You can remove AcceptButton from form and set the KeyPreview property on the form that'll handle its KeyDown event. There you can check for the Enter key and take the action accordingly.
This is one of the feature of the form i.e.
if button does not have a focus if you still want desired code to be executed when user click Enter...
Set the AcceptButton property of a form to allow users to click a button by pressing the ENTER even if the button does not have focus.
Regards.
Try This One In VB>net
If CType(Me.ActiveControl, Button).Name = Button1.Name Then
End If

Categories