If your Silverlight application performs intensive updates to the UI during mouse events, the UI can freeze because it is invalidated before it has a chance to render. This post describes a technique for ‘throttling’ mouse events to ensure that each time an event occurs, the UI has the opportunity to render.
Introduction – the problem
The visual tree of a Silverlight / WPF uses the retained mode graphics rendering style, where the tree forms a model of the graphics which are rendered to the screen. Any changes that are made to the visual tree by adding / removing objects or changing the properties of an object within the tree, are automatically rendered to your computer screen at some point in the future.
This graphics style makes the development of complex graphics far easier than with the immediate mode counterpart. You add objects, make changes to them, and these changes are reflect on the screen by some background magic. This works just fine most of the time, however, if you continually make changes to the visual tree, without yielding, the ‘process’ which updates the UI does not have the opportunity to run, and your UI is starved.
I have found that this problem occurs most often when handling mouse events, particularly MouseMove and MouseWheel. Both of these events have the opportunity to fire very rapidly. If, when handling one of these events you make some change to the visual tree, there is the possibility that the event may be raised again before these changes are reflected on the screen. For a demonstration of this, have a play with the following simple example:
The application above creates funky patterns that track the current mouse position:
private void MainPage_MouseMove(object sender, MouseEventArgs e) { AddNewLine(e.GetPosition(this)); } /// <summary> /// Adds a new line at the given position /// </summary> private void AddNewLine(Point position) { if (_lastPosition != null) { // find the angle in which the mouse is moving double angleOfMovement = RaidansToRadians(Math.Atan2( _lastPosition.Value.Y - position.Y, _lastPosition.Value.X - position.X)) + 90; // move our current angle slightly in this direction double diff = DifferenceBetweenAngles(_angle, angleOfMovement); _angle = _angle + DifferenceBetweenAngles(_angle, angleOfMovement) / 10; // create a line double dx = Math.Sin(DegreesToRadians(_angle)) * diff; double dy = Math.Cos(DegreesToRadians(_angle)) * diff; Line line = new Line() { X1 = position.X + dx, Y1 = position.Y + dy, X2 = position.X - dx, Y2 = position.Y - dy, Opacity = 0.7, Stroke = new SolidColorBrush(Colors.Black), Tag = new Data() { Angle = _angle, Length = diff, Position = position } }; // add to canvas LineContainer.Children.Add(line); // rotates all the lines that are currently displayed RotateLines(); } _lastPosition = position; }
Everything works just fine when there are < 1000 lines on screen, however as more lines are added, the act of adding a new line to the visual tree becomes more expensive. As a result, the work needed to handle each event becomes so great that the UI is starved. If you move the mouse rapidly across the display, you will find that nothing happens until you stop moving your mouse, then all of a sudden the new lines appear.
Interestingly the background animation (which is performed on the Tick of a DispatcherTimer) does not starve the UI.
Throttling – the solution!
So, what to do? The answer is to throttle the event.

No, I don’t mean that kind of throttle, I mean throttle as in “to suppress or regulate the flow of”.
What we need to do is ensure that the changes we make to the visual tree within our MouseMove event are reflected in the UI before we make a subsequent change. Fortunately the Silverlight / WPF frameworks expose a static CompositionTarget.Rendering event which can be used for this purpose. This event is fired just before a frame is rendered. Therefore, to throttle the effect of the mouse event, we set a flag to indicate that we are waiting for a change to be rendered, then reset this flag just before rendering occurs.
I have wrapped this concept up in a simple class that provides a ThrottledMouseMove event:
/// <summary> /// Creates a 'throttled' MouseMove event which ensures that the UI /// rendering is not starved. /// </summary> public class ThrottledMouseMoveEvent { private bool _awaitingRender = false; private UIElement _element; public ThrottledMouseMoveEvent(UIElement element) { _element = element; element.MouseMove += new MouseEventHandler(Element_MouseMove); } public event MouseEventHandler ThrottledMouseMove; private void Element_MouseMove(object sender, MouseEventArgs e) { if (!_awaitingRender) { // if we are not awaiting a render as a result of a previously handled event // raise a ThrottledMouseMove event, and add a Rendering handler so that // we can determine when this event has been acted upon. OnThrottledMouseMove(e); _awaitingRender = true; CompositionTarget.Rendering += CompositionTarget_Rendering; } } private void CompositionTarget_Rendering(object sender, EventArgs e) { _awaitingRender = false; CompositionTarget.Rendering -= CompositionTarget_Rendering; } /// <summary> /// Raises the ThrottledMouseMove event /// </summary> protected void OnThrottledMouseMove(MouseEventArgs args) { if (ThrottledMouseMove!=null) { ThrottledMouseMove(_element, args); } } }
The _awaitingRender flag ensure that we do not starve the UI. Note, the CompositionTarget.Rendering event handler removes itself after handling the event, this is because the presence of the handler causes Silverlight to continuously animate.
To use this code simply substitute the regular MouseMove event handler with our throttled event:
// standard mouse move event handling MouseHandler.MouseMove += new MouseEventHandler(MainPage_MouseMove); // Replace with ... // throttled mouse move event handling var throttledEvent = new ThrottledMouseMoveEvent(MouseHandler); throttledEvent.ThrottledMouseMove += new MouseEventHandler(ThrottledEvent_ThrottledMouseMove);
As a result, the UI remains responsive:
Throttling the Mouse Wheel event
The MouseWheel event is another mouse event that fires very rapidly and can result in the UI becoming frozen. Again, the same technique can be used to throttle this event. However, with the MouseMove event, the event arguments carry the current mouse position, the MouseWheel event carries just the mouse wheel position delta. If we simply suppress events that occur before render, the UI will not respond correctly, with a smaller delta being applied than is required.
The code shown below is a slightly more complex class for throttling the MouseWheel event. This class aggregates all the MouseWheel events that occur before the UI is rendered, supplying a total delta:
/// <summary> /// A class that adapts the MouseWheel event for a UIElement to ensure that /// multiple events are not handled and acted upon without the UI being re-rendered. /// </summary> public class ThrottledMouseWheelEvent { #region fields /// <summary> /// Source element for the MouseWheel event /// </summary> private UIElement _source; /// <summary> /// The combined mouse-wheel delta /// </summary> private int _combinedDelta; /// <summary> /// A flag that indicates that a ThrottledMouseWheel event has been raised and we are waiting for /// the next Rendering event. /// </summary> private bool _awaitingRender = false; #endregion #region public API /// <summary> /// A 'throttled' MouseWheel event /// </summary> public event EventHandler<ThrottledMouseWheelEventArgs> ThrottledMouseWheel; public ThrottledMouseWheelEvent(UIElement source) { _source = source; _source.MouseWheel += new MouseWheelEventHandler(Source_MouseWheel); } #endregion #region private methods private void CompositionTarget_Rendering(object sender, EventArgs e) { Debug.WriteLine("CompositionTarget.Rendering Fired"); if (_awaitingRender) { // if we have stored delta values, raise another ThrottledMouseWheel events if (_combinedDelta != 0) { OnThrottledMouseWheel(_combinedDelta); } _combinedDelta = 0; _awaitingRender = false; } CompositionTarget.Rendering -= CompositionTarget_Rendering; } /// <summary> /// Handles mouse wheel events from the source, either firing the ThrottledMouseWheel event, /// or queueing the event until a render has occured. /// </summary> private void Source_MouseWheel(object sender, MouseWheelEventArgs e) { Debug.WriteLine("Mousewheel Event e.Delta: " + e.Delta.ToString()); if (!_awaitingRender) { // if we are not awaiting a render as a result of a previously handled event // raise a ThrottledMouseWheel event, and add a Rendering handler so that // we can determine when this event has been acted upon. OnThrottledMouseWheel(e.Delta); _combinedDelta = 0; _awaitingRender = true; CompositionTarget.Rendering += CompositionTarget_Rendering; } else { // if we are awaiting a render, store this delta value _combinedDelta += e.Delta; } } /// <summary> /// Raises the ThrottledMouseWheel event. /// </summary> protected void OnThrottledMouseWheel(int delta) { if (ThrottledMouseWheel != null) { ThrottledMouseWheel(_source, new ThrottledMouseWheelEventArgs() { Delta = delta }); } } #endregion } /// <summary> /// Provides data for the ThrottledMouseWheel event. /// </summary> public class ThrottledMouseWheelEventArgs : EventArgs { public int Delta { get; internal set; } }
The following application combines both of these throttled mouse event handlers:
You can download the full source for this blog post: SilverlightEventThrottling.zip
Regards, Colin E.




Interesting, but what makes the SL UI responsive seems to make the browser UI unresponsive…? I was just playing with the second embedded SL instance here. As I added more lines, it would take longer to switch to a different browser tab by clicking on the tab. Also, the mouse wheel stopped working. If I clicked Reset in the SL app, things would work normally again. The first embedded SL instance shows 0 lines. My environment is SL4 on FF 3.6.3 on Windows 7.
@Tom,
Thanks for the feedback – I have experienced that problem before, where a Silverlight application eats up all the available CPU time, starving the browser UI. However, it does not happen for me with the application on this page. It is something I definitely intend to look into.
Regards, Colin E.
[...] Throttling Silverlight Mouse Events to Keep the UI Responsive (Colin Eberhardt) [...]
Very nice demo!
[...] Throttling Silverlight Mouse Events to Keep the UI Responsive – Colin Eberhardt takes a ,ook at improving the responsiveness of his Silverlight applications which make use of the mouse events by throttling the mouse events, illustrating with some browser based examples (NB some of these examples show the unthrottled case which may cause your browser to become unresponsive) [...]
@Daniel,
Thanks for your input and a suggestion of an alternative approach. Silverlight has the same Dispatcher concept, but lacks the priority. I am interested to hear how your WPF solution works. If mouse events generate a lot of UI work, and you create a stack of pending events, doesn’t this mean that when you stop moving the mouse, there will be a pause as these ‘events’ are processed? Or do you have some mechanism for consolidating these events into a single action?
Regards, Colin E.
Hi !
to solve similar problems in the WPF world, I would execute the code that responds to mouse events with a given priority (so the mouse handling pipeline doesn’t choke), or I would push a frame with a given priority into the dispatcher thread in order to force the processing of a stack of pending “events” above the given threshold.
Not being familiar with Silverlight, my question is: would the WPF approach be applicable here ?
Regards, Daniel
Throttling Silverlight Mouse Events to Keep the UI Responsive | Colin Eberhardt’s Adventures in WPF…
Thank you for submitting this cool story – Trackback from DotNetShoutout…