Deep Zoom Demo now with Mouse Wheel Support

I’ve updated my Deep Zoom demo to add mouse wheel support for zooming. There is no way to capture mouse wheel events in managed code in Silverlight 2 so I tried a couple of approaches. Firstly I tried to attach a managed event handler to the DOMMouseScroll event on the HTML DOM’s window object. I didn’t get very far with this – I got the HTML bridge stuff working okay (ie registering a scriptable object via HtmlPage.RegisterScriptableObject() and attributing up my class and methods with ScriptableType and ScriptableMember respectively) but the DOMMouseScroll event never seemed to fire.

I then turned to trusty old JavaScript and, with the help of Jeff Prosise and the documentation managed to get that working. Note that I think there are a couple of errors in the current documentation. In "Calling Managed Code from Client Script" they talk about adding the ScriptableMember attribute but I couldn’t see mention of adding the ScriptableType attribute to your class. I needed to do this to get the HTML bridge stuff working (above). Then on the JavaScript side, they have some sample code in the documentation:

<script type="text/javascript">
var ajaxCtl = null;
function pluginLoaded(sender){
    ajaxCtl  = sender.get_element();
    alert(ajaxCtl.Content.mySLapp.MyToUpper("Test String"));

Where they say sender.get_element() I think that should be sender.GetHost().

On the managed code side, all I did was add the following to my Page constructor:

HtmlPage.RegisterScriptableObject("slApp", this);

And attribute up the Page class and relevant methods eg

public partial class Page : UserControl

And I added a Zoom method I could call without passing a zoom origin:

public void Zoom(double ZoomFactor)
    Point P = new Point(0.5, 0.5);
    this.msi.ZoomAboutLogicalPoint(ZoomFactor, P.X, P.Y);

For the JavaScript, I hooked up the onLoad event on my plug-in and added the following:

var ajaxCtl = null;
function pluginLoaded(sender) {
        ajaxCtl  = sender.GetHost();
        if (window.addEventListener) {
            window.addEventListener('DOMMouseScroll', OnMouseWheelTurned, false);
        window.onmousewheel = document.onmousewheel = OnMouseWheelTurned;

function OnMouseWheelTurned(event) {
    var delta = 0;

        if (!event) {
            event = window.event;
        if (event.wheelDelta) {
            delta = event.wheelDelta;

            if (window.opera) {
                delta = -delta;
            else if (event.detail) {
                delta = -event.detail;

            if (delta) {

                if (delta > 0) {
                else {

        if (event.preventDefault) {
        event.returnValue = false;

The bulk of which comes pretty much verbatim from Jeff’s post. Note the call the the Zoom() managed method (ajaxCtl.Content.slApp.Zoom()) from the JavaScript event handler.

The finished result is here.

Update: I’ve just noticed that my zooming isn’t quite right as I don’t take account of an offset zoom origin of the image has been panned. So needs a bit more work but it’ll have to wait ’til I’m back in from Mix…

UpdateAgain: No it wont, I simply changed the Zoom() method to:

public void Zoom(double ZoomFactor)
        this.msi.ViewportOrigin.X, this.msi.ViewportOrigin.Y);

ie the ViewPortOrigin is the logical place to use as the zoom origin rather than (0.5,0.5) as I had before.

Technorati Tags: ,

Comments (6)

  1. DanielMoth says:

    Once you get the idea to use the HTML Bridge, that’s when you realise you don’t need any script at all – do it all in managed code (using AttachEvent). I updated mine to that effect.

  2. MikeO [MSFT] says:

    I’d like to see your source for that Daniel because as I said, I didn’t manage to get it working when I played with it so I reverted to JavaScript. It seemed like it should be pretty easy to hook a managed code event handler to the mouse wheel event but for some reason my handler would never fire. Not sure I still have my non-working version but would be interesting to see yours – I might be able to spot where I went wrong. Mike

  3. DanielMoth says:

    Mike, I pointed to the source as a reply to your comment on my blog. Reading your blog post again, I think that essentially, you need to catch two other JS events as well…

    On a separate note, I see that everybody who has played with multiscaleimage seems to be using their own zoom in/out constants. Maybe there should be a usability study to find the "correct" ones 🙂

  4. Daniel left a comment on my post about mouse wheel support saying he&#39;d managed to get it working

  5. MikeO [MSFT] says:

    Daniel – no it was nothing to do with other JS events. The reason it works for you and not me is simply because you ignore the 0 return value for eventObject.GetProperty("detail"). It seems like you get an awful lot of 0s and the occassional +/- value. Ignoring them provides a solution but it’s not perfect – the sensitivity between IE and FireFox is quite different. Anyway, I have it working now in exactly the same way as you – ie only zooming for a + or – value and doing nothing for 0 (so I wrapped my call to Zoom() in an If statement testing for wheelData != 0. Mike

  6. It has been three weeks since we annouced Silverlight 2 at MIX08. Many of you are excited to getting