Question

I have a numericUpDown control (Windows Forms).

enter image description here

I want to listen to the ValueChanged event.

I set it in the properties and it works.

But:

I want that i can "scroll" up or down. (If I make this longer it will be faster)

When I'm done with the "scroll", I want that the event xyz is fired now and not during the scrolling.

How can I do that?

Was it helpful?

Solution

Try using the mouseup event. It fires when you take your finger off of the left mouse button, so in theory it should solve your issue.

[Edited by James] Try this control on your form.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Example.CustomControl
{
    /// <summary>
    /// Provides an extra event for the numericUpDown control that fires after the value stops scrolling.
    /// </summary>
    public class NumericDelayedChange : NumericUpDown
    {
        /// <summary>
        /// Flag that the value has actually changed.
        /// </summary>
        /// <devdoc>
        /// Just in case the control was clicked somewhere other than the up/down buttons.
        /// </devdoc>
        private bool valueHasChanged = false;

        /// <summary>
        /// Fires when the value has stopped being scrolled.
        /// </summary>
        public event EventHandler OnAfterScollValueChanged;

        /// <summary>
        /// Captures that value as having changed.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnValueChanged(EventArgs e)
        {
            valueHasChanged = true;
            base.OnValueChanged(e);
        }

        /// <summary>
        /// Captures the mouse up event to identify scrolling stopped when used in combination with the value changed flag.
        /// </summary>
        /// <param name="mevent"></param>
        protected override void OnMouseUp(MouseEventArgs mevent)
        {
            base.OnMouseUp(mevent);
            if (mevent.Button == System.Windows.Forms.MouseButtons.Left)
            {
                PerformOnAfterScollValueChanged();
            }
        }

        /// <summary>
        /// Captures the key up/down events to identify scrolling stopped when used in combination with the value changed flag.
        /// </summary>
        /// <param name="mevent"></param>
        protected override void OnKeyUp(KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down)
            {
                PerformOnAfterScollValueChanged();
            }
            base.OnKeyUp(e);
        }

        /// <summary>
        /// Checks the value changed flag and fires the OnAfterScollValueChanged event.
        /// </summary>
        private void PerformOnAfterScollValueChanged()
        {
            if (valueHasChanged)
            {
                valueHasChanged = false;
                if (OnAfterScollValueChanged != null) { OnAfterScollValueChanged(this, new EventArgs()); }
            }
        }
    }
}

OTHER TIPS

You need to define what is I'm done with the scroll. This could be removing the mouse from the scroll button, or a certain time passed since the last click. In any case, I don't think you can cause the event not to run, but you can do some checks in the event handler. For example:

private DateTime? lastClickTime;
public void MyUpDown_ValueChanged(object sender, EventArgs e)
{
    if (lastClickTime != null && DateTime.Now.Subtract(lastClickTime.Value).Seconds > someInterval)
    {
        // Do the work
    }

    lastClickTime = DateTime.Now
}

But, as I said, you need first to define what is I'm done. This code is not perfect.

Here's a direct way of approaching the problem: Just check if a mouse button is being pressed with Control.MouseButtons, like this:

private void numericUpDown1_ValueChanged(object sender, EventArgs e)
    {
        //don't update until done scrolling
        if (Control.MouseButtons == MouseButtons.None)
        {
            // Do the work
        }
    }

Here's how I solved this problem:

A task checks a "valueIsChanging" flag. This flag is set by the ValueChanged event. After this flag stops being set to True by the ValueChanged event, the while loop completes and your code is executed.

Task waitForValueSettleTask;
volatile bool valueIsChanging; // marked volaltile since it is access by multiple threads (the GUI thread, and the task)

private void numericUpDown_ValueChanged(object sender, EventArgs e)
{
    valueIsChanging = true;

    if (waitForValueSettleTask == null || waitForValueSettleTask != null &&
    (waitForValueSettleTask.IsCanceled || waitForValueSettleTask.IsCompleted || waitForValueSettleTask.IsFaulted))
    {
        waitForValueSettleTask = Task.Run(() =>
        {
            while (valueIsChanging)
            {
                valueIsChanging = false;
                Thread.Sleep(1000); // Set this to whatever settling time you'd like
            }

            // Your code goes here
        });
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top