I have a bound NumericUpDown control.
I want the ValueChanged
Event to fire when either the up or down arrow is clicked or if the user changes the number.
When the up or down arrow is clicked the ValueChanged
event does fire,
but not when I just type into the control.
// numericUpDownDiscountRate
//
this.numericUpDownDiscountRate.DecimalPlaces = 4;
this.numericUpDownDiscountRate.Location = new System.Drawing.Point(133, 344);
this.numericUpDownDiscountRate.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.numericUpDownDiscountRate.Name = "numericUpDownDiscountRate";
this.numericUpDownDiscountRate.Size = new System.Drawing.Size(115, 23);
this.numericUpDownDiscountRate.TabIndex = 78;
this.numericUpDownDiscountRate.ValueChanged += new System.EventHandler(this.numericUpDownDiscountRate_ValueChanged);
I found a question that advises to use the KeyPress event However the keypress event happens before the value is updated.
How do I get the value of the control from within the key press?
private void numericUpDownDiscountPercent_KeyPress(object sender, KeyPressEventArgs e)
{
if (loadingForm) return;
try
{
loadingForm = true;
var updn = sender as NumericUpDown;
// updn.value does not include the key press and I don't know how to construct the value
MyCalculateRate(updn?.Value ?? 0);
loadingForm = false;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Discount rate Key Press");
loadingForm = false;
}
}
Since the Value
is changed only after validation, which occurs when the input is validated when the internal Edit Control loses focus or when the Value is retrieved, I suggest to introduce a custom value that works alongside the default Value
property.
Note that when the Value Property is read, the input is not just validated but also the Text is re-set, so reading the Value
Property while editing becomes quite difficult, since the caret is moved when the Text is reset.
When the Up/Down Buttons are pressed, also the Text is formatted, hence OnTextChanged()
is called and the custom value is set.
Implemented in a Custom Control here, but you can do ~the same using the event handlers of a standard NumericUpDown Control.
Don't read the Value
property in OnValueChanged()
, for the reasons previously explained.
Use CurrentEditValue
while the Text is being edited. Or subscribe to the CurrentEditValueChanged
event instead.
The Custom Control is DataBinding-friendly.
using System.ComponentModel;
using System.Windows.Forms;
[ToolboxItem(true), DesignerCategory("code")]
public class NumericUpDownEx : NumericUpDown {
private static readonly object Event_CurrentEditValueChanged = new object();
private decimal m_CurrentEditValue = 0M;
public NumericUpDownEx() { }
[Bindable(true), Browsable(false), EditorBrowsable(EditorBrowsableState.Always)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual decimal CurrentEditValue {
get => m_CurrentEditValue;
internal set {
if (value != m_CurrentEditValue) {
m_CurrentEditValue = value;
OnCurrentEditValueChanged(EventArgs.Empty);
}
}
}
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
if (decimal.TryParse(Text, out decimal value)) {
CurrentEditValue = value;
OnValueChanged(e);
}
}
public event EventHandler CurrentEditValueChanged {
add {
Events.AddHandler(Event_CurrentEditValueChanged, value);
}
remove {
Events.RemoveHandler(Event_CurrentEditValueChanged, value);
}
}
protected virtual void OnCurrentEditValueChanged(EventArgs e)
{
if (Events[Event_CurrentEditValueChanged] is EventHandler evth) evth(this, e);
}
}
Example of direct (One-Way) Binding to the CurrentEditValue
Property:
[SomeTextBox].DataBindings.Add("Text", numericUpDpwnEx1, "CurrentEditValue", true, DataSourceUpdateMode.OnPropertyChanged);