私はnumericUpDownコントロール(Windowsフォーム)を持っています。
イベントを聴きたいですValueChanged
。
プロパティで設定すると動作します。
だが:
上下に「スクロール」できるようにしたいと思います。(これを長くすると速くなります)
「スクロール」が終了したら、スクロール中ではなく、イベントxyzが発生するようにします。
どうやってやるの?
私はnumericUpDownコントロール(Windowsフォーム)を持っています。
イベントを聴きたいですValueChanged
。
プロパティで設定すると動作します。
だが:
上下に「スクロール」できるようにしたいと思います。(これを長くすると速くなります)
「スクロール」が終了したら、スクロール中ではなく、イベントxyzが発生するようにします。
どうやってやるの?
mouseupイベントを使用してみてください。マウスの左ボタンから指を離すと発火するので、理論的には問題は解決するはずです。
[Jamesが編集]フォームでこのコントロールを試してください。
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()); }
}
}
}
}
とは何かを定義する必要があります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
。このコードは完全ではありません。
問題に直接アプローチする方法は次のとおりです。次のように、でマウスボタンが押されているかどうかを確認しますControl.MouseButtons
。
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
//don't update until done scrolling
if (Control.MouseButtons == MouseButtons.None)
{
// Do the work
}
}
この問題を解決した方法は次のとおりです。
タスクは「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
});
}
}