Aug 242011
 

There are situations in which you need to do some processing when an event fires but you don’t want to do it every time if the event happens in a very short time interval. Such a situation can occur for example when handling MouseMove events – you want to do the processing when the mouse stops for a certain amount of time, but not for every intermediate position of the mouse.

 Reusable deferred action execution mechanism

I have created a reusable class that accomplishes this task. The class uses a timer internally and defers the execution until the timer interval elapses. If the event fires during the timer interval, the timer interval is reset. The current implementation uses a DispatcherTimer to execute the event (because I use it in UI-related code), but can be easily changed to use another timer if you need it.

Using the LazyAction class is straightforward. You need to declare a field of type LazyAction:

 1: private readonly LazyAction lazyAction;

Somewhere (probably in the constructor) you need to initialize it:

 1: public MyClass()


 

 2: {                 this.lazyAction = new LazyAction(TimeSpan.FromMilliseconds(10), DoSomething);


 

 3: }

The constructor of the lazy action has two parameters:

  • deferredUpdateDelay – the time interval from the last call to Execute after which the action really gets executed
  • action – the action to execute

Suppose you handle the MouseMove event inside your class, you would execute the lazy action like this:

 1: private void canvas_MouseMove(object sender, MouseEventArgs e)


 

 2: {     this.lazyAction.Execute();


 

 3: }

There is just one caveat in using this approach – unit testing (at least using MSUnit) does not work as expected. The reason is that by using the DispatcherTimer inside our class, the timer won’t fire when running unit tests. This is caused by the fact that during running the unit tests the Dispatcher doesn’t automatically process its queue. A workaround for this is using the DispatcherUtil class found in this StackOverflow discussion: http://stackoverflow.com/questions/1106881/using-the-wpf-dispatcher-in-unit-tests 

Get the code here: LazyAction.zip