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.