什么是最简单的方法来处理事件,只有一段时间后,最后一次触发
本文关键字:一段时间 最后一次 什么 最简单 方法 处理事件 | 更新日期: 2023-09-27 18:01:45
我有事件处理程序:
private void Control_Scroll(object sender, ScrollEventArgs e)
{
UpdateAnnotations();
}
现在我希望只有当用户停止滚动时才更新注释,比如自从上次滚动事件通过100ms后,然后执行动作,否则丢弃它,因为它无论如何都无关紧要。
最简单/可重用的方法是什么?最好是一些静态方法,如public static void DelayedAction(Action action, TimeSpan delay)
。
使用。net 4.0
查看对Rx(响应式扩展)问题的回答。(你可以使用Observable。从事件中创建一个可观察对象)
我会这样写
class MyClass
{
private System.Timers.Timer _ScrollTimer;
public MyClass()
{
_ScrollTimer= new System.Timers.Timer(100);
_ScrollTimer.Elapsed += new ElapsedEventHandler(ScrollTimerElapsed);
}
private void ResetTimer()
{
_ScrollTimer.Stop();
_ScrollTimer.Start();
}
private void Control_Scroll(object sender, ScrollEventArgs e, TimeSpan delay)
{
ResetTimer();
}
private void ScrollTimerElapsed(object sender, ElapsedEventArgs e)
{
_ScrollTimer.Stop();
UpdateAnnotations();
}
}
每次用户滚动,计时器重置,只有当滚动停止100毫秒TimerElapsed被触发,你可以更新你的注释
我同时在表单上尝试了几个控件,并且它可以被外部重用。
private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
if (DelayedAction(100, sender))
UpdateAnnotations();
}
Dictionary<object, Timer> timers = new Dictionary<object, Timer>();
bool DelayedAction(int delay, object o)
{
if (timers.ContainsKey(o))
return false;
var timer = new Timer();
timer.Interval = delay;
timer.Tick += (s, e) =>
{
timer.Stop();
timer.Dispose();
lock(timers)
timers.Remove(o);
};
lock(timers)
timers.Add(o, timer);
timer.Start();
return true;
}
字典是锁定的,因为如果用户不能同时点击两个控件,则可能在删除另一个控件的同时插入一个计时器。
试试这个类:
public class ActionHelper
{
private static Dictionary<Delegate, System.Threading.Timer> timers =
new Dictionary<Delegate, System.Threading.Timer>();
private static object lockObject = new object();
public static void DelayAction(Action action, TimeSpan delay)
{
lock (lockObject)
{
System.Threading.Timer timer;
if (!timers.TryGetValue(action, out timer))
{
timer = new System.Threading.Timer(EventTimerCallback, action,
System.Threading.Timeout.Infinite,
System.Threading.Timeout.Infinite);
timers.Add(action, timer);
}
timer.Change(delay, TimeSpan.FromMilliseconds(-1));
}
}
public static void EventTimerCallback(object state)
{
var action = (Action)state;
lock (lockObject)
{
var timer = timers[action];
timers.Remove(action);
timer.Dispose();
}
action();
}
}
特点:
- <
- Thead安全/gh>
- 支持多个并发操作
用法:
private void Control_Scroll(object sender, ScrollEventArgs e)
{
ActionHelper.DelayAction(UpdateAnnotations, TimeSpan.FromSeconds(1));
}
请注意,该方法是在单独的线程中调用的。如果你需要做UI工作,你需要使用Control.Invoke
(WinForms)或Dispatcher.Invoke
(WPF):
// The method is contained in a Form (winforms)
private void UpdateAnnotations()
{
if (this.InvokeRequired)
this.Invoke(new Action(UpdateAnnotations));
else
{
MessageBox.Show("Method is called");
}
}
是否可以不存储事件被触发的时间(DateTime. now),并且当它被调用时检查自上次(例如DateTime. now)以来已经过了多长时间。Now - lastExecutionTime> minTime)
** Update **
或者基于静态帮助器思想的更通用的方式:
public static void DelayedAction(Action action, TimeSpan delay)
{
var delayedActionTimer = new Timer(x => action(), null, delay, TimeSpan.FromMilliseconds(-1));
}
显然需要工作…例如,您可以将计时器存储在一个字段中,并在用户每次滚动