键入时未触发 NumericUpDown ValueChanged 事件

NumericUpDown ValueChanged event not firing while typing

我有绑定的 NumericUpDown 控件。

我希望 ValueChanged 事件在单击向上或向下箭头或用户更改数字时触发。

单击向上或向下箭头时,ValueChanged 事件会触发, 但不是当我只是输入控件时。

// 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);

我发现了一个建议使用 KeyPress event 的问题 但是,按键事件发生在值更新之前。

如何从按键中获取控件的值?

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;
    }
}

这有点“花言巧语”,但是(在 .netfw472 中 - 尚未在 netcore 中尝试过)如果您将事件处理程序绑定到访问值的 KeyUp:

    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
    }

它会导致您的 ValueChanged 在每次按键时触发,并且在 ValueChanged 中访问 .Value 将为您提供当前值..

“但是为什么?!”你可能会问...“我不知道;我从来没有看过..但是 NumericUpDown 不被认为是最可靠的控件..”

由于 Value 仅在验证后更改,这发生在内部编辑控件失去焦点或检索值时验证输入时,我建议引入一个 自定义 值与默认 Value 属性.

一起使用

请注意,当读取值 属性 时,输入不仅经过验证而且文本也是 re-set,因此在编辑时读取 Value 属性变得相当困难,因为插入符号在重置文本时移动。

当按下 Up/Down 按钮时,文本也会被格式化,因此会调用 OnTextChanged() 并设置自定义值。

在此处的自定义控件中实现,但您可以使用标准 NumericUpDown 控件的事件处理程序执行相同的操作。
由于前面解释的原因,请不要阅读 OnValueChanged() 中的 Value 属性。
在编辑文本时使用 CurrentEditValue。或者改为订阅 CurrentEditValueChanged 事件。
自定义控件是 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);
    }
}

直接 (One-Way) 绑定到 CurrentEditValue 的示例 属性:

[SomeTextBox].DataBindings.Add("Text", numericUpDpwnEx1, "CurrentEditValue", true, DataSourceUpdateMode.OnPropertyChanged);