Michael Michael - 3 months ago 54
C# Question

Update Value of the NumericUpDown control without raising of ValueChanged event (Winforms)

I need to update a Value of the NumericUpDown control without raising of ValueChanged event (WinForms, C#).

The simple way is to remove event handler like:

numericUpDown.ValueChanged -= numericUpDown_ValueChanged;


After that to set the needed value:

numericUpDown.Value = 15;


And to add the event handler again:

numericUpDown.ValueChanged += numericUpDown_ValueChanged;


The problem is that I want to wright method that will get the NumericUpDown control as a first parameter, needed value as a second parameter and will update the value in the way that was given below.

To do it, I need to find the connected event handler for the ValueChanged event (for each NumericUpDown it's different).

I searched a lot, but didn't find the solution that would work for me.

My last try was:

private void NumericUpDownSetValueWithoutValueChangedEvent(NumericUpDown control, decimal value)
{
EventHandlerList events = (EventHandlerList)typeof(Component).GetField("events", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField).GetValue(control);
object current = events.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField)[0].GetValue(events);
List<Delegate> delegates = new List<Delegate>();
while (current != null)
{
delegates.Add((Delegate)GetField(current, "handler"));
current = GetField(current, "next");
}
foreach (Delegate d in delegates)
{
Debug.WriteLine(d.ToString());
}
}
public static object GetField(object listItem, string fieldName)
{
return listItem.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField).GetValue(listItem);
}


After running of NumericUpDownSetValueWithoutValueChangedEvent function, the
object current
is equal to null, so no one EventHandler was not found (I tried it on the Form - all event handlers were found).

Answer

Have you tried changing just the internal value and updating the text instead? That way you can bypass the eventhandler being fired.

If you take a look at the source code ( http://referencesource.microsoft.com/System.Windows.Forms/winforms/Managed/System/WinForms/NumericUpDown.cs.html#0aaedcc47a6cf725 ) You will see that the property Value is using a private field called currentValue this is the value you would like to set. And afterwards just do control.Text = value.ToString();

Example

private void SetNumericUpDownValue(NumericUpDown control, decimal value)
{
    if (control == null) throw new ArgumentNullException(nameof(control));
    var currentValueField = control.GetType().GetField("currentValue", BindingFlags.Instance | BindingFlags.NonPublic);
    if (currentValueField != null)
    {
        currentValueField.SetValue(control, value);
        control.Text = value.ToString();
    }
}

This hasnt been tested but I'm pretty sure it will work. :) Happy coding!