Extending Silverlight’s mouse events

If you just want the extension method library or source, jump to the bottom. If not, read on…

Silverlight is pretty limited when it comes to mouse events. Out of the box, you only have five events you can subscribe to on a given element:

Notice that there is no such thing as click, double-click, drag, right-click and mouse-wheel.

Click and double click you can create from the up/down events. If the mouse doesn’t move between up and down, its a click, and if it happens two times within a timespan, it’s a double-click. Similarly, a drag is a click with mouse movement in-between down and up. Using extension methods, we can easily extent the UIElement class with two new methods for each event: Attach[eventname] and Detach[eventname], that takes care of this tracking. I earlier described this approach for defining a double click extension. These are all types of gestures we often need, so creating a reusable library with these extensions is a no-brainer.

When it comes to mouse wheel, it gets slightly trickier. We can’t do this using existing Silverlight events. Instead we can use the JavaScript bridge to detect wheel events in the browser, and bubble them into the plugin. First we listen to the JavaScript event on the entire plugin, and then inside Silverlight we use the Enter/Leave events to track whether the mouse is over the element you are listening to events on. However there are cases where this wouldn’t work:

  • The application is running in full screen.
  • The Silverlight plugin is running with HTML access explicitly disabled.
  • The .xap file is hosted on a different domain than the page hosting it.
  • You are running the application in Silverlight 3’s Out-of-browser mode.

All of them are cases where the JavaScript bridge is disabled.

Lastly right-click. This is a whole different story. When you right-click a Silverlight page, it will should you a small context menu with a link to the Silverlight settings. This can’t be overridden, but using the same approach as for Wheel, you can intercept the event using JavaScript and prevent the bubbling to the plugin. However this only works reliably in Internet Explorer, and most secondly only if you run the application in windowless mode.

UPDATE: Right-click now also work in Mozilla browsers. See here

I took all these events, and wrapped the, into a little set of extension method, so you don’t have to write the code over and over again.

To use it, download the library (link at the bottom) and add a reference to the DLL. Then at the top of the class where you want to use the event extensions, add the following to your using statements:

using SharpGIS.MouseExtensions;

When you have done this, you will instantly get new intellisense on any object that inherits from UIElement:

image

You will see seven new Attach* and Detach* methods:

Click Mouse/Down without moving the mouse
DoubleClick Two quick clicks
Drag Mouse down, move, mouse up. Event will fire for each mouse movement.
Hover If the mouse stops over an element and stays in the same place for a short time.
KeyClick Click while the user is holding down a key.
RightClick Windowless only!
Wheel Mouse wheel

You can see a live sample of it in action here.

Assembly Library that you can reference in your project: Download binary (7.14 kb)

Sourcecode and sample application is available here:Download source (24.79 kb)

Comments (3) -

  • Morten,
    I have been playing with the mouse extensions and found some problems.
    The functions Attach/Detach and the raising the handlers is not thread-safe.
    My application was crashing because of it.
    So one thing I added to the code for myself is this:

    MouseButtonEventHandler[] temps = new MouseButtonEventHandler[handlers.Count];
    handlers.CopyTo(temps, 0);
    foreach (MouseButtonEventHandler handler in temps)
    {
    ...
    }

    Without this, the foreach may crash if you modify the contents of the handlers on the same thread as the event callback.
  • Brad thank you for the comment. You are right that you shouldn't be changing the handlers collection in the eventhandler delegates, and thank you for the workaround.
    However this is not a thread safety issue. You said it yourself: "if you modify the handlers on the same thread". The usual theading issue is multiple threads accessing the same object, which is not the case here. The implementation is handled in the UI thread only.
Comments are closed