I have a bound numeric updown control.
I want the Value Changed 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 Value Changed 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;
}
}
CodePudding user response:
It's a bit "hocus pocus" but (in .netfw472 - haven't tried in netcore) if you bind an event handler to KeyUp that accesses the Value:
private void numericUpDown1_KeyUp(object sender, KeyEventArgs e)
{
var v = numericUpDown1.Value; //I know it looks useless, but it seems to make ValueChanged fire more often
}
it causes your ValueChanged to fire on every keypress and accessing .Value
within ValueChanged will give you the current value..
"But why?!" you might ask... "I don't know; I've never looked.. but NumericUpDown isn't regarded as the most reliable control.."
CodePudding user response:
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.
public class NumericUpDownEx : NumericUpDown {
public NumericUpDownEx() { }
public virtual decimal CurrentEditValue { get; internal set; } = 0M;
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
// Use CurrentCulture as IFormatProvider
if (decimal.TryParse(Text, out decimal v)) {
CurrentEditValue = v;
OnValueChanged(e);
}
}
protected override void OnValueChanged(EventArgs e)
{
Console.WriteLine($"OnValueChanged: CurrentEditValue={CurrentEditValue}");
base.OnValueChanged(e);
}