RX可能是最简单的选择,特别是如果您已经在应用程序中使用它。但如果没有,添加它可能有点过度。
对于基于UI的应用程序(如WPF),我使用以下类来使用DispatcherTimer:
public class DebounceDispatcher
{
private DispatcherTimer timer;
private DateTime timerStarted { get; set; } = DateTime.UtcNow.AddYears(-1);
public void Debounce(int interval, Action<object> action,
object param = null,
DispatcherPriority priority = DispatcherPriority.ApplicationIdle,
Dispatcher disp = null)
{
timer?.Stop();
timer = null;
if (disp == null)
disp = Dispatcher.CurrentDispatcher;
timer = new DispatcherTimer(TimeSpan.FromMilliseconds(interval), priority, (s, e) =>
{
if (timer == null)
return;
timer?.Stop();
timer = null;
action.Invoke(param);
}, disp);
timer.Start();
}
}
使用方法:
private DebounceDispatcher debounceTimer = new DebounceDispatcher();
private void TextSearchText_KeyUp(object sender, KeyEventArgs e)
{
debounceTimer.Debounce(500, parm =>
{
Model.AppModel.Window.ShowStatus("Searching topics...");
Model.TopicsFilter = TextSearchText.Text;
Model.AppModel.Window.ShowStatus();
});
}
键盘空闲200毫秒后才处理按键事件 - 之前的待处理事件将被丢弃。
还有一个Throttle方法,总是在给定的时间间隔之后触发事件:
public void Throttle(int interval, Action<object> action,
object param = null,
DispatcherPriority priority = DispatcherPriority.ApplicationIdle,
Dispatcher disp = null)
{
timer?.Stop();
timer = null;
if (disp == null)
disp = Dispatcher.CurrentDispatcher;
var curTime = DateTime.UtcNow;
if (curTime.Subtract(timerStarted).TotalMilliseconds < interval)
interval = (int) curTime.Subtract(timerStarted).TotalMilliseconds;
timer = new DispatcherTimer(TimeSpan.FromMilliseconds(interval), priority, (s, e) =>
{
if (timer == null)
return;
timer?.Stop();
timer = null;
action.Invoke(param);
}, disp);
timer.Start();
timerStarted = curTime;
}