Skip to content

Instantly share code, notes, and snippets.

@zacharyyates
Last active March 24, 2017 01:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zacharyyates/2b2e74b19125758d107a to your computer and use it in GitHub Desktop.
Save zacharyyates/2b2e74b19125758d107a to your computer and use it in GitHub Desktop.
A basic event debouncer for .NET, similar to http://underscorejs.org/#debounce
using System;
using System.Collections.Generic;
using System.Timers;
public static class Events {
static Dictionary<EventHandler, Timer> _debounceTimers;
public static EventHandler Debounce(TimeSpan interval, Action<object, EventArgs> action, ISynchronizeInvoke synchronizingObject = null) {
object lastSender = null;
EventArgs lastArgs = null;
var timer = new Timer();
if (_debounceTimers == null)
_debounceTimers = new Dictionary<EventHandler, Timer>();
timer.Interval = interval.TotalMilliseconds;
timer.SynchronizingObject = synchronizingObject;
timer.Elapsed += (sender, args) => {
timer.Enabled = false;
timer.Stop();
action(lastSender, lastArgs);
};
EventHandler handler = (sender, args) => {
lastSender = sender;
lastArgs = args;
timer.Stop();
timer.Start();
timer.Enabled = true;
};
_debounceTimers.Add(handler, timer);
return handler;
}
public static void DisposeDebouncers(this EventHandler handler) {
handler.ThrowIfNull("handler");
if (_debounceTimers.ContainsKey(handler)) {
var timer = _debounceTimers[handler];
if (timer != null) {
timer.Stop();
timer.Enabled = false;
timer.Dispose();
}
}
}
}
public class EventExtensionsTest {
event EventHandler FrequentEvent;
[Fact]
void DebounceTest() {
var counter = 0;
var span = TimeSpan.FromSeconds(1);
var handler = EventExtensions.Debounce(span, (sender, e) => counter++);
FrequentEvent += handler;
FrequentEvent(this, null);
FrequentEvent(this, null);
FrequentEvent(this, null);
Thread.Sleep(2000);
Assert.Equal(1, counter);
FrequentEvent(this, null);
FrequentEvent(this, null);
FrequentEvent(this, null);
FrequentEvent(this, null);
FrequentEvent(this, null);
Thread.Sleep(2000);
Assert.Equal(2, counter);
FrequentEvent.DisposeDebouncers();
FrequentEvent -= handler;
}
}
@pmunin
Copy link

pmunin commented Mar 24, 2017

This is not thread safe. At least _debounceTimers dictionary must be ConcurrentDictionary instead

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment