简体   繁体   English

键入时未触发 NumericUpDown ValueChanged 事件

[英]NumericUpDown ValueChanged event not firing while typing

I have a bound NumericUpDown control.我有一个绑定的 NumericUpDown 控件。

I want the ValueChanged Event to fire when either the up or down arrow is clicked or if the user changes the number.我希望在单击向上或向下箭头或用户更改数字时触发ValueChanged事件。

When the up or down arrow is clicked the ValueChanged event does fire, but not when I just type into the control.单击向上或向下箭头时,会触发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);

I found a question that advises to use the KeyPress event However the keypress event happens before the value is updated.我发现了一个建议使用KeyPress 事件的问题,但是 keypress 事件发生在值更新之前。

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

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:如果您将事件处理程序绑定到访问值的 KeyUp,这有点“骗局”但是(在 .netfw472 中 - 尚未在 netcore 中尝试过):

    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..它会导致您的 ValueChanged 在每次按键时触发,并且在 ValueChanged 中访问.Value将为您提供当前值..

"But why?!" “但为什么?!” you might ask... "I don't know; I've never looked.. but NumericUpDown isn't regarded as the most reliable control.."你可能会问……“我不知道;我从来没有看过……但是 NumericUpDown 不被认为是最可靠的控件……”

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.由于仅在验证后更改Value ,当内部编辑控件失去焦点或检索值时验证输入时会发生这种情况,因此我建议引入与默认Value属性一起使用的自定义值。

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.请注意,当读取 Value 属性时,不仅验证了输入,而且还重置了 Text,因此在编辑时读取Value属性变得非常困难,因为在重置 Text 时会移动插入符号。

When the Up/Down Buttons are pressed, also the Text is formatted, hence OnTextChanged() is called and the custom value is set.当按下向上/向下按钮时,文本也会被格式化,因此调用OnTextChanged()并设置自定义值。

Implemented in a Custom Control here, but you can do ~the same using the event handlers of a standard NumericUpDown Control.在此处在自定义控件中实现,但您可以使用标准 NumericUpDown 控件的事件处理程序执行相同操作。
Don't read the Value property in OnValueChanged() , for the reasons previously explained.不要阅读OnValueChanged()中的Value属性,原因前面已经解释过了。
Use CurrentEditValue while the Text is being edited.在编辑文本时使用CurrentEditValue Or subscribe to the CurrentEditValueChanged event instead.或者改为订阅CurrentEditValueChanged事件。
The Custom Control is DataBinding-friendly.自定义控件是 DataBinding 友好的。

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:直接(单向)绑定到CurrentEditValue属性的示例:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM