(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Using the MultiscaleImage control in Silverlight

(4 votes)
Martin Mihaylov
>
Martin Mihaylov
Joined Oct 29, 2007
Articles:   50
Comments:   70
More Articles
5 comments   /   posted on May 30, 2008
Categories:   Controls

This article is compatible with the latest version of Silverlight.

Introduction

The last article I wrote was about the DeepZoom Composer. It explained how to manage images with it. This time I’ll try to show how to use the created images with the Silverlight MulitscaleImage control.

You can download the source code or view the live demo here:

MultiscaleImageDemo.zip

Live Demo

Overview

Let’s add our MultiscaleImage control to the xaml and set its source:

 <Grid x:Name="Layout" Background="Black">
      <MultiScaleImage  x:Name="MyMultiscaleImage" Source="/demo/info.bin"
            Width="400" Height="300"></MultiScaleImage>
 </Grid>

Note! I placed my demo directory in the ClientBin folder and if you want it to be placed in your project folder, the path should look like that "../demo/info.bin".

 MyMultiscaleImage.Source = new DeepZoomImageTileSource( new Uri( "/demo/dzc_output.xml",  UriKind.Relative ) );

If you run your application at this time, the image will be loaded and you’ll see how smoothly it will be done. The next thing we want to add to our application is zooming.

Zooming

Using buttons

There several ways to zoom our image using the MultiscaleImage control. The first one is via buttons. In our case we’re going to use two repeat buttons – one for zoom in and one for zoom out.

 <Grid x:Name="Layout" Background="Black">
      <MultiScaleImage  x:Name="MyMultiscaleImage" Source="/demo/info.bin"
            Width="400" Height="300"></MultiScaleImage>
  
      <RepeatButton x:Name="ZoomIn" Width="80" Height="30"
            HorizontalAlignment="Left" Content="Zoom In"
            Click="ZoomIn_Click"></RepeatButton>
  
      <RepeatButton x:Name="ZoomOut" Background="DarkCyan" Width="80"
            Height="30" HorizontalAlignment="Right" Content="Zoom Out"
            Click="ZoomOut_Click"></RepeatButton>
 </Grid>

Next we create methods for the Click events of the buttons:

 private void ZoomIn_Click( object sender, RoutedEventArgs e )
 {
        Point p = MyMultiscaleImage.ElementToLogicalPoint( new Point(
              MyMultiscaleImage.Width / 2, ( MyMultiscaleImage.Width /
              MyMultiscaleImage.AspectRatio ) / 2 ) );
        MyMultiscaleImage.ZoomAboutLogicalPoint( 1.1, p.X, p.Y );
 }
  
 private void ZoomOut_Click( object sender, RoutedEventArgs e )
 {
        Point p = MyMultiscaleImage.ElementToLogicalPoint( new
              Point(MyMultiscaleImage.Width / 2, (MyMultiscaleImage.Width /
              MyMultiscaleImage.AspectRatio ) / 2 ) );
        MyMultiscaleImage.ZoomAboutLogicalPoint( 0.9, p.X, p.Y );
 }

Here p is the point that will be the center of our zoom, in this case the center of the image. To zoom we use the ZoomAboutLogicalPoint method which takes the zoomfactor and the coordinates of the zoom point as parameters.

Note! Most of the methods workwith logical points, so we use the method ElementToLogicalPoint of the MulitscaleImage Control to convert the element points to logical. Also when we use buttons we have to zoom around the center of the control.

Using mouse double click

Another way to zoom the image is to use mouse double click for zoom in and combine it with some key (Alt, Ctrl, Shift etc.) for zoom out. The most important here is the time between the clicks because it determines whether there is a double click or not. The event we need is MouseLeftButtonDown and here is the sample code:

 private long lastTicks = 0;
 private void MyMultiscaleImage_MouseLeftButtonDown( object sender, MouseButtonEventArgs e )
 {
    if( ( DateTime.Now.Ticks - lastTicks ) < 2310000 )
    {
        Point p = e.GetPosition( MyMultiscaleImage );
        Point zoomCenter = MyMultiscaleImage.ElementToLogicalPoint( p );
        if( ( Keyboard.Modifiers & ModifierKeys.Alt ) == ModifierKeys.Alt )
            MyMultiscaleImage.ZoomAboutLogicalPoint( 0.9, zoomCenter.X, zoomCenter.Y );
        else
            MyMultiscaleImage.ZoomAboutLogicalPoint( 1.1, zoomCenter.X, zoomCenter.Y );
        return;
    }
 
    lastTicks = DateTime.Now.Ticks;
 }

We use ticks to measure the time between the clicks. If it’s not longer than 2310000 ticks we have a double click and we zoom in or out, depending on if the Alt key is pressed. Otherwise,we set the value of the lastTicks variable.

Note! When we were zooming using the buttons, we zoomed around the center of the control. Here on every double click we get the current position of the mouse, so we can zoom around that position.

Using the mouse wheel

First, create an event handler for the mouse wheel. Here is some code:

 Point lastMousePosition = new Point();
 
 public Page()
 {
    InitializeComponent();
     
    MyMultiscaleImage.MouseWheel += ( s, e ) =>
    {
        double zoomFactor = 1;
 
        e.Handled = true;
        if( e.Delta > 0 )
            zoomFactor = 1.1;
        else
            zoomFactor = 0.9;
 
        Point p = MyMultiscaleImage.ElementToLogicalPoint(
            this.lastMousePosition );
        MyMultiscaleImage.ZoomAboutLogicalPoint( zoomFactor, p.X, p.Y );
    };
 }
 
 private void MyMultiscaleImage_MouseMove( object sender, MouseEventArgs e )
 {
    this.lastMousePosition = e.GetPosition( MyMultiscaleImage );
 }

In the mouse move event we set the value of the lastMousePosition property. Later we will use it to determine our zoom center when the MouseWheel event is raised. The MouseWheelEvent argument has a property delta which contains the direction of the wheel (Delta > 0 for direction away from the user and Delta < 0 for direction towards the user).

These were three ways to zoom an image, now let’s try to move the zoomed image around.

Panning

It’s very annoying when you’ve zoomed an image and are not able to slide it and pan it around in order to see all of the details. You have to zoom out and then zoom in again at a different position. So the next step is to add some panning to the image. First we need a few help variables. One for the drag offset one for the current position of the mouse and one flag for the dragging.

 bool dragInProgress = false;
 Point dragOffset;
 Point currentPosition;

We add the following code to the MyMultiscaleImage_MouseLeftButtonDown event handler.

 dragInProgress = true;
 dragOffset = e.GetPosition( MyMultiscaleImage );
 currentPosition = MyMultiscaleImage.ViewportOrigin;

After that we create handlers for the MouseLeftButtonUp and MouseLeave events too:

 private void MyMultiscaleImage_MouseLeftButtonUp( object sender, MouseButtonEventArgs e )
 {
    dragInProgress = false;
 }
  
 private void MyMultiscaleImage_MouseLeave( object sender, MouseEventArgs e )
 {
    dragInProgress = false;
 }

The panning is done in the MouseMove event. Let’s take a look at the code:

 private void MyMultiscaleImage_MouseMove( object sender, MouseEventArgs e )
 {
    this.lastMousePosition = e.GetPosition( MyMultiscaleImage );
 
    if( dragInProgress )
    {
        Point newOrigin = new Point();
        newOrigin.X = currentPosition.X - ( ( ( e.GetPosition( 
MyMultiscaleImage ).X - dragOffset.X ) / 
MyMultiscaleImage.ActualWidth ) * MyMultiscaleImage.ViewportWidth );
 
        newOrigin.Y = currentPosition.Y - ( ( ( e.GetPosition( 
MyMultiscaleImage ).Y - dragOffset.Y ) /                        MyMultiscaleImage.ActualHeight ) * MyMultiscaleImage.ViewportWidth );
        MyMultiscaleImage.ViewportOrigin = newOrigin;
    }
 }

Here we use the ViewportOrigin and the ViewportWidth properties of the MultiscaleImage control. The ViewportOrigin adjusts where the image is focused. The ViewportWidth controls the zoom factor and is used to calculate the new ViewportOrigin for the image.

Summary

These are the basics of the MultiscaleImage control. Now we know how to display our image in it and also how to zoom it and pan it. In the next articles we’ll try to make our Silverlight application even richer and more interactive.

You can find the demo to this article here and the source code here.

Conclusion

This article is just a brief description of the key features of the MultiscaleImage control. It targets the developer who has just started with the Silverlight controls. Any comments are welcomed.


Subscribe

Comments

  • -_-

    RE: Using the MultiscaleImage control in Silverligth2 Beta 1


    posted by Anatoly on Sep 08, 2008 01:40

    Very cool post...

  • -_-

    Using the MultiscaleImage control in Silverligth2 Beta 1


    posted by Sasko on Jan 24, 2009 15:55

    Thanks

  • -_-

    RE: Using the MultiscaleImage control in Silverligth 2


    posted by Glenn on May 31, 2009 01:47
    Thanks for posting this great article. I've been able to implement all of the code.
  • lnikolov

    RE: Using the MultiscaleImage control in Silverlight


    posted by lnikolov on Jan 06, 2011 16:28
    The article has been updated to the latest version of Silverlight and Visual Studio.
  • pouya_devil

    Re: Using the MultiscaleImage control in Silverlight


    posted by pouya_devil on Aug 03, 2011 09:23

    Hi very nice Article

    but im using the deep zoom and i store my images and their tile in the database so im loading one image in my msi and it's work fine but i dont know how can i load all my image at once like your project

    can u help me ???

    my project is based on this sample

    http://www.codeproject.com/KB/silverlight/DatabaseDeepZoom.aspx

Add Comment

Login to comment:
  *      *