I have a C# WinForm application where I want to implement a NumericUpDown component that increments / decrements its value depending whether or not the control key is pressed on clicking to the arrow button. If the control key is pressed, it should increment by 1, by 0.1 otherwise. Using the ValueChanged event does not work, because the value has already changed. I also tried to use the Click and MouseClick event but they are risen after the ValueChanged Event.
Has anyone an Idea how I can achieve this?
// This method added to either Click or MouseClick event
private void Click_Event(object sender, EventArgs e)
{
if (Control.ModifierKeys == Keys.Control)
{
numSetPoint1.Increment = 1; // Setting the Increment value takes effect on the next click
}
else
{
numSetPoint1.Increment = 0.1m;
}
}
// Event added to ValueChanged
private void ValueChanged_Event(object sender, EventArgs e)
{
// the same here
}
One way to do this is by making a CustomNumericUpDown control and swapping out all instances of the regular NumericUpDown control in your designer file.
Then you can just override the methods that implement the value up-down at the source and call the base class or not depending on the static value of Control.ModifierKeys property.
class CustomNumericUpDown : NumericUpDown
{
public CustomNumericUpDown() => DecimalPlaces = 1;
public override void UpButton()
{
if(ModifierKeys.Equals(Keys.Control))
{
Value += 0.1m;
}
else
{
// Call Default
base.UpButton();
}
}
public override void DownButton()
{
if (ModifierKeys.Equals(Keys.Control))
{
Value -= 0.1m;
}
else
{
base.DownButton();
}
}
}
You can implement it at form level.
https://learn.microsoft.com/en-us/dotnet/desktop/winforms/input-keyboard/how-to-handle-forms?view=netdesktop-6.0
Handle the KeyPress or KeyDown event of the startup form, and set the
KeyPreview property of the form to true.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.ControlKey)
{
numSetPoint1.Increment = 1;
}
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.ControlKey)
{
numSetPoint1.Increment = 0.1m;
}
}
Related
I have a UserControl like following:
public partial class TextControlBox : UserControl
{
public TextControlBox()
{
Window.Current.CoreWindow.KeyDown += CoreWindow_KeyDown;
}
private void CoreWindow_KeyDown(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.KeyEventArgs e)
{
if(e.VirtualKey == VirtualKey.Tab)
{
//insert tabkey into textbox
}
}
}
The problem is when I add the UserControl into my Mainpage.xaml which also contains other controls, the tab-key moves the focus to the next control but
I would like it to insert a tab character (\t) into my textbox instead.
How can I archive this?
I tried handling the event using e.Handled = true if the tab-key is pressed but this did not work.
It seems that you will need to use UIElement.KeyDown Event instead of the CoreWindow.KeyDown Event. CoreWindow.KeyDown Event will not raise when the Tab key is pressed because it's a system key.
Here is the code that I'm using and it works:
public MyUserControl1()
{
this.InitializeComponent();
this.KeyDown += MyUserControl1_KeyDown;
}
private void MyUserControl1_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.Tab)
{
e.Handled = true;
//insert tabkey into textbox
}
Debug.WriteLine("MyUserControl1_KeyDown");
}
Under certain conditions I'd like to cancel the ValueChanged event of a NumericUpDown control in Winforms (e.g. when the value set in the control is too high in relation to another value in a TextBox).
However, the EventArgs passed as argument into the event handler for the NumericUpDown control doesn't offer anything like "Cancel", so how can I do it?
private void nudMyControl_ValueChanged(object sender, EventArgs e)
{
// Do some stuff, but only if the value is within a certain range.
// Otherwise, cancel without doing anything.
}
You probably can handle this situation by using Minimum & maximum Properties, yet there are some solutions.
One way to do it is by creating a custom control, although it is nasty in my idea.
public partial class CustomNumericUpDown : NumericUpDown
{
public CustomNumericUpDown()
{
InitializeComponent();
}
protected override void OnTextBoxKeyDown(object source, KeyEventArgs e)
{
if (MyCustomCondition())
{
e.Handled = true;
}
base.OnTextBoxKeyDown(source, e);
}
private bool MyCustomCondition()
{
var checkOut = false;
//if (something == foo)
//{
checkOut = true;
//}
return checkOut;
}
}
You also can do stuff for ValueChanged:
This is some dummy sample, yet you can change it in your way:
public virtual decimal CurrentEditValue { get; internal set; } = 0M;
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
if (decimal.TryParse(Text, out decimal v))
{
CurrentEditValue = v;
OnValueChanged(e);
}
}
protected override void OnValueChanged(EventArgs e)
{
// if(CurrentEditValue == foo) Do_stuff.
base.OnValueChanged(e);
}
I have a user control that has the following overridden event:
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.Left )
DoSomething();
}
When I place the user control on my Main Form, this event is not fired.
How can I access this event from Parent form?
protected override void OnKeyDown(KeyEventArgs e)
{
e.Handled = true;
if (e.KeyCode == Keys.Left)
Move(pt.X,pt.Y);//Move is a function within the usercontrol
else if (e.KeyCode == Keys.Right)
Move(pt.X,pt.Y);
//other conditions
e.Handled = false;
}
I need the parent to be notified on this event
If I understand correctly, you are trying to invoke the OnKeyDown method of the user control from within the parent form.
This is the main form class:
public class Form1 : Form
{
private UserControl1 myControl;
public Form1()
{
myControl = new UserControl1();
Controls.Add(myControl);
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
myControl.InvokeOnKeyDown(e);
}
}
And this is the User Control:
public class UserControl1 : UserControl
{
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
MessageBox.Show("Key Down Fired!");
}
public void InvokeOnKeyDown(KeyEventArgs e)
{
OnKeyDown(e);
}
}
Edit regarding arrow keys: the arrow keys are not normally considered to be input keys and therefore are not passed on to the key methods. To change this you must override the IsInputKey method as such:
protected override bool IsInputKey(Keys e)
{
if (e == Keys.Up || e == Keys.Down ||
e == Keys.Left || e == Keys.Right) return true;
return base.IsInputKey(e);
}
Following your updated question and code example posted, if you want the parent Form to be notified that a move operation took place, you need to create an event in the UserControl and subscribe to it in the parent form. This could be achieved in the following example. Please let me know if this solves your problem, else please post further detail.
Best regards
// Define custom EventArgs to pass into the Move event
public class MoveEventArgs : EventArgs
{
private Point _movePoint;
public MoveEventArgs(Point movePoint)
{
_movePoint = _movePoint;
}
public Point MovePoint { get { return _movePoint; } }
}
// Define a custom user control that raises an event to subscribers on move
public class MyUserControl : UserControl
{
public event EventHandler<MoveEventArgs> Moved;
protected override void OnKeyDown(KeyEventArgs e)
{
e.Handled = true;
if (e.KeyCode == Keys.Left)
{
Move(pt.X,pt.Y);//Move is a function within the usercontrol
OnMoved(pt);
}
else if (e.KeyCode == Keys.Right)
{
Move(pt.X,pt.Y);
OnMoved(pt);
}
//other conditions
e.Handled = false;
}
// Raises a custom event, Moved
protected void OnMoved(Point movePoint)
{
var handler = Moved;
if (handler != null)
{
handler(this, new MoveEventArgs(movePoint);
}
}
}
// How to subscribe to the event (and be notified of move)
public class MyParentForm : Form
{
public MyParentForm()
{
InitializeComponent();
_myUserControl.Moved += new EventHandler<MoveEventArgs>(MyUserControl_Moved);
}
private void MyUserControl_Moved(object sender, MoveEventArgs e)
{
// e.MovePoint now contains the point that the usercontrol was moved to
// this event will fire whenever the user presses Left or Right arrow
}
}
I have a Form that closes itself when the ESC key is pressed, thanks to KeyPreview, ProcessKeyEventArgs, ProcessCmdKey or whatever. But I have a Control on that form that does very relevant things when ESC is pressed (it hides itself) and the Form should not be closed when that happens.
The control uses the KeyDown event and sets the SuppressKeyPress flag to true, but that happens after the aforementioned form key preview, thus having no effect.
Is there some sort KeyPostview ?
How do I not close the form when a Control has a relevant use of a key hit ?
Edit: The control handling ESC is a textbox embedded in a hand-maid ListView. The textbox appears when the user clicks a cell, enabling edition. To validate the new text, ENTER would be nice (that already works, as giving the focus to anything else). To cancel edition, ESC seems most natural.
You are competing Big Time over the Escape key. Along with the Enter key, that's a very important key in the standard Windows user interface. Just drop a button on form and set the form's CancelButton property to some other button, that will suck the keystroke to that button.
To compete with that, you have to create a control that tells Winforms that you really think that the Escape key is more important. That requires overriding the IsInputKey property. Like this:
using System;
using System.Windows.Forms;
class MyTexBox : TextBox {
protected override bool IsInputKey(Keys keyData) {
if (keyData == Keys.Escape) return true;
return base.IsInputKey(keyData);
}
protected override void OnKeyDown(KeyEventArgs e) {
if (e.KeyData == Keys.Escape) {
this.Text = ""; // for example
e.SuppressKeyPress = true;
return;
}
base.OnKeyDown(e);
}
}
OK - this works:
class CustomTB : TextBox
{
public CustomTB()
: base()
{
CustomTB.SuppressEscape = false;
}
public static bool SuppressEscape { get; set; }
protected override void OnKeyDown(KeyEventArgs e)
{
CustomTB.SuppressEscape = (e.KeyCode == Keys.Escape);
base.OnKeyUp(e);
}
}
In your form:
public Form1()
{
InitializeComponent();
this.KeyPreview = true;
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape && !CustomTB.SuppressEscape)
{
this.Close();
}
CustomTB.SuppressEscape = false;
}
Can you check to see what control has the focus first? If there's only one control on your form that does something relevant with the escape key, check to see if that's the control that has the focus before you close the form.
The basic problem is that the form's Dispose method is called when Close is called, so the form is going to close and there's not much you can do about it.
I would get around this by having the UserControl implement a marker interface, say ISuppressEsc. The form's KeyUp handler can then locate the currently focused control and cancel the close if the focused control implements ISuppressEsc. Be aware that you will have to do extra work to find the focused control if it may be a nested control.
public interface ISuppressEsc
{
// marker interface, no declarations
}
public partial class UserControl1 : UserControl, ISuppressEsc
{
public UserControl1()
{
InitializeComponent();
}
private void textBox1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
textBox1.Text = DateTime.Now.ToLongTimeString();
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
KeyPreview = true;
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
var activeCtl = ActiveControl;
if (!(activeCtl is ISuppressEsc) && e.KeyCode == Keys.Escape)
{
Close();
}
}
}
I have a few text boxes on my UI that I want to display the mobile keyboard for when the control has focus, then go away.
Note: for this particular program, it is a tall screen and has no physical keyboard on the device.
Add an InputPanel to your Form, hook up the GotFocus and LostFocus events of the TextBox and show/hide the input panel in the event handlers:
private void TextBox_GotFocus(object sender, EventArgs e)
{
SetKeyboardVisible(true);
}
private void TextBox_LostFocus(object sender, EventArgs e)
{
SetKeyboardVisible(false);
}
protected void SetKeyboardVisible(bool isVisible)
{
inputPanel.Enabled = isVisible;
}
Update
In response to ctacke's request for completeness; here is sample code for hooking up the event handlers. Normally I would use the designer for this (select the textbox, show the property grid, switch to the event list and have the environment set up handlers for GotFocus and LostFocus), but if the UI contains more than a few text boxes you may wish to have it more automated.
The following class exposes two static methods, AttachGotLostFocusEvents and DetachGotLostFocusEvents; they accept a ControlCollection and two event handlers.
internal static class ControlHelper
{
private static bool IsGotLostFocusControl(Control ctl)
{
return ctl.GetType().IsSubclassOf(typeof(TextBoxBase)) ||
(ctl.GetType() == typeof(ComboBox) && (ctl as ComboBox).DropDownStyle == ComboBoxStyle.DropDown);
}
public static void AttachGotLostFocusEvents(
System.Windows.Forms.Control.ControlCollection controls,
EventHandler gotFocusEventHandler,
EventHandler lostFocusEventHandler)
{
foreach (Control ctl in controls)
{
if (IsGotLostFocusControl(ctl))
{
ctl.GotFocus += gotFocusEventHandler;
ctl.LostFocus += lostFocusEventHandler ;
}
else if (ctl.Controls.Count > 0)
{
AttachGotLostFocusEvents(ctl.Controls, gotFocusEventHandler, lostFocusEventHandler);
}
}
}
public static void DetachGotLostFocusEvents(
System.Windows.Forms.Control.ControlCollection controls,
EventHandler gotFocusEventHandler,
EventHandler lostFocusEventHandler)
{
foreach (Control ctl in controls)
{
if (IsGotLostFocusControl(ctl))
{
ctl.GotFocus -= gotFocusEventHandler;
ctl.LostFocus -= lostFocusEventHandler;
}
else if (ctl.Controls.Count > 0)
{
DetachGotLostFocusEvents(ctl.Controls, gotFocusEventHandler, lostFocusEventHandler);
}
}
}
}
Usage example in a form:
private void Form_Load(object sender, EventArgs e)
{
ControlHelper.AttachGotLostFocusEvents(
this.Controls,
new EventHandler(EditControl_GotFocus),
new EventHandler(EditControl_LostFocus));
}
private void Form_Closed(object sender, EventArgs e)
{
ControlHelper.DetachGotLostFocusEvents(
this.Controls,
new EventHandler(EditControl_GotFocus),
new EventHandler(EditControl_LostFocus));
}
private void EditControl_GotFocus(object sender, EventArgs e)
{
ShowKeyboard();
}
private void EditControl_LostFocus(object sender, EventArgs e)
{
HideKeyboard();
}
Use the InputPanel class. Enable it when you get focus, disable it when you lose focus.