I have a .NET TextBox with AutoComplete feature on the form. The form has also AcceptButton and CancelButton defined. If I try to commit a suggestion with Enter key or close drop down with Esc, my form closes.
How can I prevent this behavior?
Do not assign AcceptButton and CancelButton form properties. Set DialogResult in the buttons OnClick event.
Simple way is to remove AcceptButton and CancelButton properties while you are in auto-complete textbox:
public Form1()
{
InitializeComponent();
txtAuto.Enter +=txtAuto_Enter;
txtAuto.Leave +=txtAuto_Leave;
}
private void txtAC_Enter(object sender, EventArgs e)
{
AcceptButton = null;
CancelButton = null;
}
private void txtAC_Leave(object sender, EventArgs e)
{
AcceptButton = btnOk;
CancelButton = btnCancel;
}
instead to Accept and Cancel buttons you can go for the following approach:
Set KeyPreview property for the form to true.
Handle the KeyDown event of the form, in the handler method you can have something similar to the below code
switch (e.KeyCode)
{
case Keys.Enter:
{
if (!txtAuto.Focused)
{
Save();
}
break;
}
case Keys.Escape:
{
if (!txtAuto.Focused)
{
Close();
}
break;
}
}
Another option is to derive your own custom TextBox class that performs validation when Enture/Return is pressed:
public class MyTextBox : TextBox
{
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Enter || keyData == Keys.Return)
{
// Perform validation here
return true;
}
else
return false;
}
}
Related
I want to display message that button is unclickable (I have used Enabled option, button1.Enabled = false/true; ). Does anyone know how to detect if button is clicked, when it is unclickable in order to display error message "Button is unclickable...".
Windows forms, C#
Whenever a standard control doesn't behave in exactly the way that need it to, all we usually have to do is make our own version that inherits the standard control so that we can make it do whatever we want. Your question offers a great reason for doing that because a normally a disabled Button is not going to fire a Click or a MouseDown event.
Here is a guideline example for a custom Button that:
Intercepts the Enabled property by declaring it new.
Leaves the base class button always responsive because it's always enabled.
Paints the control as dimmed if disabled.
Suppresses the firing of the Click event if disabled, and fires DisabledClick instead.
Look in the Title Bar to see when the button is clicked.
ButtonWithDisabledOption class
class ButtonWithDisableOption : Button
{
bool _enabled = true;
public new bool Enabled
{
get => _enabled;
set
{
if (!Equals(_enabled, value))
{
_enabled = value;
OnEnabledChanged(EventArgs.Empty);
}
}
}
protected override void OnEnabledChanged(EventArgs e)
{
base.OnEnabledChanged(e);
if(Enabled)
{
ForeColor = SystemColors.ControlText;
BackColor = SystemColors.Control;
FlatStyle = FlatStyle.Standard;
}
else
{
ForeColor = Color.FromArgb(191, 191, 191);
BackColor = Color.FromArgb(204, 204, 204);
FlatStyle = FlatStyle.Flat;
}
}
protected override void OnClick(EventArgs e)
{
if (Enabled)
{
base.OnClick(e);
}
else
{
DisabledClick?.Invoke(this, EventArgs.Empty);
}
}
public event EventHandler DisabledClick;
}
MainForm.Designer.cs
Be sure to replace Button references with ButtonWithDisabledOption.
private void InitializeComponent()
{
// this.buttonWithDisableOption = new System.Windows.Forms.Button();
this.buttonWithDisableOption = new button_with_disabled_option.ButtonWithDisableOption();
...
}
// private System.Windows.Forms.Button button1;
private button_with_disabled_option.ButtonWithDisableOption buttonWithDisableOption;
TEST
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
buttonWithDisableOption.Enabled = checkBoxButtonEnabled.Checked = true;
// Button events
buttonWithDisableOption.Click += buttonWithDisableOption_Click;
buttonWithDisableOption.DisabledClick += buttonWithDisableOption_DisabledClick;
// CheckBox events
checkBoxButtonEnabled.CheckedChanged += checkBoxButtonEnabled_CheckedChanged;
}
private void checkBoxButtonEnabled_CheckedChanged(object sender, EventArgs e)
{
buttonWithDisableOption.Enabled = checkBoxButtonEnabled.Checked;
}
private void buttonWithDisableOption_Click(object sender, EventArgs e)
{
// Title bar
Text = $"Button Click {_tstcount++} (Enabled)";
}
private void buttonWithDisableOption_DisabledClick(object sender, EventArgs e)
{
// Title bar
Text = $"Button Click {_tstcount++} (Disabled)";
MessageBox.Show("Button is unclickable");
}
int _tstcount = 1;
}
So, apparently I had some problem when handling keys such as F10 or F11.
I want to move the focus from current textbox into another textbox, but not in one particular textbox. So, I wrote some code to handle key:
private void checkKeys(KeyEventArgs e)
{
if (e.KeyCode == Keys.F10)
{
buyerName.Focus();
}
else if (e.KeyCode == Keys.F11)
{
discount.Focus();
}
}
But, if I put this into individual textbox, which kinda hassle to me. Is there any method to listen key whether in global userControl or textbox?
Edit : here's my structure that I want to ask :
Form-
|-User Control
|-TextBox
Edit 2 : here's some image might help img
To use a global keyboard listener in Winforms, you just need to add a handler to KeyUp action for the main form itself:
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.F10)
{
textBox1.Focus();
e.Handled = true; //To use F10, you need to set the handled state to true
} else if (e.KeyCode == Keys.F11)
{
textBox2.Focus();
}
}
Then make sure that the KeyPreview property on the main form is set to True.
The issue with the application freezing when pressing F10 is because it is waiting for another consecutive action. To bypass this simply set the Handled property on the keyevent to TRUE. This releases the unresolved event.
This is my entire form class, refactored to use a helper method as you are refering to. This works fine. But you have to make sure that the KeyPreview property on your form is True, unless your keypresses will not be matched to your event handlers.
namespace KeyTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
CheckKeys(e);
}
private void CheckKeys(KeyEventArgs e)
{
if (e.KeyCode == Keys.F10)
{
textBox1.Focus();
e.Handled = true;
}
else if (e.KeyCode == Keys.F11)
{
textBox2.Focus();
e.Handled = true;
}
}
}
}
Now in your comment you are mentioning a UserControl, if you want that, then you need to create an instance method on your UserControl class, and pass the event to that from your global keyboard event handler on your main form.
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public void HandleKeys(KeyEventArgs e)
{
if (e.KeyCode == Keys.F10)
{
textBox1.Focus();
e.Handled = true;
}
else if (e.KeyCode == Keys.F11)
{
textBox2.Focus();
e.Handled = true;
}
}
}
Then on your main form:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
CheckKeys(e);
}
private void CheckKeys(KeyEventArgs e)
{
uc1.HandleKeys(e); //Instance method on your user control.
}
}
This then works as intended.
As pointed out in one of the comments, a better way would be to override the ProcessCmdKey method on the Form base class. This would be done like so:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
userControl11.HandleKeys(keyData); // method on the userControl to handle the key code.
base.ProcessCmdKey(ref msg, keyData);
return true;
}
}
The handler on the UserControl stays more or less the same:
public void HandleKeys(Keys keys)
{
if (keys == Keys.F10)
{
nameTB.Focus();
} else if (keys == Keys.F11)
{
emailTB.Focus();
}
}
Whether this is a more correct way of doing it, I am unsure of. They certainly both accomplish the same result. The documentation shows the first method in for handling keyboard events at the form level here:
How to handle keyboard input
But states here that the ProcessCmdKey method is to provide additional handling of shortcuts and MDI accellerators.
ProcessCmdKey
I will leave that up to you to decide what is the best for your scenario. But keep it in to show how you would use it should you choose to.
You can hook up to the KeyUp event of your form.
That way, any key pressed while your form is focused will be send to you (if the control didn't handle the key).
Thanks to #Espen and #reza-aghaei for handling keys into main form. Unfortunately, I still didn't managed find a way to focus to designated textbox inside a UserControl. However, I make some dirty method which kinda crappy and un-efficient by searching child control from it's parent
//MainForm.cs
if(yourUserControl.Name)//Do some check for targeted userControl, if null can cause NullReferenceException
{
if (e.KeyCode == Keys.F10)
{
this.Controls.Find("textboxName", true).First().Focus();
e.Handled = true;
}
}
Is there a way to distinguish whether the Enter event on a control was raised by keyboard (Tab, Shift+Tab) or by direct mouse click?
I need to perform an action only when the user is moving to the control using Tab, but not when the user directly clicks on the control. I have tried to intercept the mouse click directly, but it seems the Enter event is raised before Click.
Instead of tracking the Tab key, you can use the WM_MOUSEACTIVATE message to detect activation of the control with the mouse. You could either sub-class each control type you use and override the WndProc method or use a NativeWindow listener class like the one presented below. Depending on how many types of controls you use, it may be less work and clutter to just sub-class those controls to provide a property that indicates that the control was selected using the mouse. It is your decision to make, but the pattern will be the same.
This code is a slight modification of the example shown in the MS documentation.
public class MouseActivateListener : NativeWindow
{
private Control parent;
public MouseActivateListener(Control parent)
{
parent.HandleCreated += this.OnHandleCreated;
parent.HandleDestroyed += this.OnHandleDestroyed;
parent.Leave += Parent_Leave;
this.parent = parent;
if (parent.IsHandleCreated)
{
AssignHandle(parent.Handle);
}
}
private void Parent_Leave(object sender, EventArgs e)
{
MouseActivated = false;
}
private void OnHandleCreated(object sender, EventArgs e)
{
AssignHandle(((Form)sender).Handle);
}
private void OnHandleDestroyed(object sender, EventArgs e)
{
ReleaseHandle();
}
public bool MouseActivated { get; set; }
[System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
const Int32 WM_MouseActivate = 0x21;
base.WndProc(ref m);
if (m.Msg == WM_MouseActivate && m.Result.ToInt32() < 3)
{
MouseActivated = true;
}
}
}
Example Usage:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private MouseActivateListener textBox1Listener;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
textBox1Listener = new MouseActivateListener(textBox1);
}
private void textBox1_Enter(object sender, EventArgs e)
{
if (textBox1Listener.MouseActivated)
{
MessageBox.Show("Mouse Enter");
}
else
{
MessageBox.Show("Tab Enter");
}
}
}
You can use the Form.KeyPreview event and store the last key press in a variable. Then in your control's Enter event, check the value of the key that was pressed last. If this is a tab, do whatever you need to:
private Keys lastKeyCode;
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
this.lastKeyCode = e.KeyCode;
}
Then in the Enter event, check it:
if (lastKeyCode == Keys.Tab)
{
// Whatever...
}
Intercepting WM_KEYUP and WM_KEYDOWN directly with a message filter to retrieve the state of the Tab key worked. This seems excessive for such a seemingly straightforward task, but apparently the Tab key is suppressed from most windows forms events.
Would be happy to take a cleaner answer, but for now, this is it:
class TabMessageFilter : IMessageFilter
{
public bool TabState { get; set; }
public bool PreFilterMessage(ref Message m)
{
const int WM_KEYUP = 0x101;
const int WM_KEYDOWN = 0x100;
switch (m.Msg)
{
case WM_KEYDOWN:
if ((Keys)m.WParam == Keys.Tab) TabState = true;
break;
case WM_KEYUP:
if ((Keys)m.WParam == Keys.Tab) TabState = false;
break;
}
return false;
}
}
class MainForm : Form
{
TabMessageFilter tabFilter;
public MainForm()
{
tabFilter = new TabMessageFilter();
Application.AddMessageFilter(tabFilter);
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
Application.RemoveMessageFilter(tabFilter);
base.OnFormClosed(e);
}
void control_Enter(object sender, EventArgs e)
{
if (tabFilter.TabState) // do something
else // do domething else
}
}
I have a calculator usercontrol, the usercontrol is added to a panel in my form:
On my main Form I have:
private void frmPOS_KeyDown(object sender, KeyEventArgs e)
{
// here I want to pass the keydown captured to my calculator
// usercontrol so the KeyDown event is fired in my usercontrol
}
In my Calculator.cs I have:
private void Calculator_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.NumPad0:
// one
lblResult.Text = "0";
break;
case Keys.NumPad1:
// one
lblResult.Text = "1";
break;
case Keys.NumPad2:
// two
lblResult.Text = "2";
break;
// .. etc
case Keys.Add:
// Plus
break;
default:
// Avoid setting e.Handled to
return;
}
e.Handled = true;
}
Any clue?
One way I have done this is by creating an event on the user control and raise it when the actual event happens. So, in the user control I would do something like...
public partial class Calculator : UserControl
{
//create an event
public event EventHandler<KeyPressEventArgs> OnKeyPressed;
public Calculator()
{
InitializeComponent();
}
private void Calculator_KeyPress(object sender, KeyPressEventArgs e)
{
//raise the event when the key press happens and someone is listening
if (OnKeyPressed != null)
{
OnKeyPressed(sender, e);
}
}
}
and then on the Main form you would subscribe to the event and handle it..
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//subscribe to the event we create on the user control
calculator1.OnKeyPressed += new EventHandler<KeyPressEventArgs>(MyKeyPressHandlerInMainForm);
}
private void MyKeyPressHandlerInMainForm(object sender, KeyPressEventArgs e)
{
//Handle the event. Here you would write your logic.
//Since you have keypressEventArgs coming in as a parameter you would be able to
//do determine what key was pressed and all that.
}
}
enter code here
You can move your switch block to a new public method in the control, eg.:
public void HandleKeyEvent(KeyEventArgs e) { ... }
This method can be invoked from your form (and your existing control event handler if you need to keep it).
As a side note, if you set the form's KeyPreview-property to true you won't get problems with a focused control incorrectly getting the event. See MSDN for more information about this property.
I have an UWP app that controls my tv. I have some Buttons, Checkboxes etc. and keyboard controls/events. This combination causes problems. When check a checkbox and then press VirtualKey.Subtract the checkbox is unchecked and I don't want any changes through keyboard. The use of e.Handled doesn't seem to work.
How can I disable default Keyboard navigation behaviour or Keyboard Focus in a UWP App?
private async void Page_Loaded(object sender, RoutedEventArgs e)
{
Window.Current.CoreWindow.KeyDown += KeyEventHandler;
Window.Current.CoreWindow.KeyUp += KeyEventHandlerDevNull;
}
private void KeyEventHandlerDevNull(CoreWindow sender, KeyEventArgs e)
{
e.Handled = true;
}
private async void KeyEventHandler(CoreWindow sender, KeyEventArgs e)
{
e.Handled = true; //gets unset in case of default
if (MainViewModel.ControlsEnabled)
{
switch (e.VirtualKey)
{
case VirtualKey.Left:
await ButtonPressLeft();
break;
case VirtualKey.Right:
await ButtonPressRight();
break;
default:
e.Handled = false;
break;
}
}
}
Sorry if this question might be a duplicate one but I think it's different for UWP (Universal Windows Platform).
You need to implement/use your custom checkbox and override the OnKeyDown Event to prevent changes to your checkbox.
public sealed partial class MyCheckBox : CheckBox
{
public MyCheckBox()
{
this.InitializeComponent();
}
protected override void OnKeyDown(KeyRoutedEventArgs e)
{
e.Handled = true;
//your logic
}
}