【问题标题】:NumericUpDown Control should fire ValueChanged Event only on scroll finishedNumericUpDown 控件应仅在滚动完成时触发 ValueChanged 事件
【发布时间】:2012-08-02 09:03:21
【问题描述】:

我有一个 numericUpDown 控件(Windows 窗体)。

我想听ValueChanged 事件。

我在属性中设置了它,它可以工作。

但是:

我希望我可以向上或向下“滚动”。 (如果我让它更长,它会更快)

当我完成“滚动”后,我希望现在触发事件 xyz 而不是在滚动期间。

我该怎么做?

【问题讨论】:

  • 您如何告诉您的代码当我完成“滚动”时。如果您需要 验证 数字输入,则使用 Validating 事件(当您离开控件时)

标签: c# winforms events numericupdown


【解决方案1】:

尝试使用 mouseup 事件。当您将手指从鼠标左键上移开时它会触发,因此理论上它应该可以解决您的问题。

[詹姆斯编辑] 在你的表单上试试这个控件。

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

【讨论】:

  • 控件不是用上/下光标键滚动到的吗?在这种情况下,鼠标向上不会触发。
  • 我想也将相同的逻辑添加到光标键。 IE。向上键,其中键是光标键以及鼠标向上。
  • 在这种情况下,创建一个 sub 来处理您想要做的事情,并在 MouseUp 和 KeyUp 事件上调用它(如果键 ups 是箭头键,并且 NumericUpDown 具有焦点)。
  • 我实际上有一个工作示例,但不要偷走你的风头!我可以编辑你的答案吗?
  • 来吧,我上周才开始学习 C#,直到那时我才拥有大约 6-8 个月的 VB 经验。我当然不是专业人士,只是有点熟练。
【解决方案2】:

您需要定义什么是I'm done with the scroll。这可能是从滚动按钮上移开鼠标,或者自上次单击后经过了一段时间。无论如何,我认为您不能导致事件不运行,但您可以在事件处理程序中进行一些检查。例如:

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
}

但是,正如我所说,您首先需要定义什么是I'm done。这段代码并不完美。

【讨论】:

    【解决方案3】:

    这是解决问题的直接方法: 只需使用Control.MouseButtons 检查是否按下了鼠标按钮,如下所示:

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

    【讨论】:

      【解决方案4】:

      我是这样解决这个问题的:

      任务检查“valueIsChanging”标志。此标志由 ValueChanged 事件设置。在 ValueChanged 事件停止将该标志设置为 True 后,while 循环完成并执行您的代码。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-06
        • 2015-10-16
        • 2020-09-12
        • 2020-08-08
        • 1970-01-01
        相关资源
        最近更新 更多