I couldn't find much in the way of documentation around this so I thought I'd post something rough here as I was playing with it.
I should caveat this by saying that this is my first attempt so don't expect it to be necessarily "right". I can't find any docs :-)
I wanted to play with MultiScaleImage in Silverlight 2 so I first went and downloaded the Deep Zoom Composer tool;
Download the Preview of the Deep Zoom Composer
and I ran it up and created a new project. Into that project I used the Import button to import all the images from my c:\windows\web\wallpaper folder;
I then went to the Compose tab and tried to lay them all out after a fashion (i.e. not very well :-));
Having done a bit of composition, I used the Export function to export this and ended up with a bunch of files - I called the export windowsbackdrops so I got;
- windowsbackdrops.sdi
- windowsbackdrops folder
- Lots of subfolders
- info.bin
- info.xml
- SparseImageSceneGraph.xml
With that in place, I started up a new Silverlight 2 Project in VS 2008.
Added a web project;
Compiled and then ( probably a bit hackily ) I went and copied into the ClientBin folder of my web project the files/folders that Deep Zoom Composer had created for me;
That's my ClientBin folder of my web app up above.
I then went and altered the XAML for my Page to read;
<UserControl
x:Class="TestDz.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid
x:Name="LayoutRoot"
Background="Gray">
<MultiScaleImage
x:Name="msi"
ViewportWidth="1.0"
Source="/windowsbackdrops/info.bin" />
</Grid>
</UserControl>
And, staggerinly, my Deep Zoom image seemed to spring into life;
Note - as far as I can figure out that ViewportWidth is "How much of this image do you want to see in your control". I'm saying 1.0 which appears to mean "all of it". Here's what it looks like at 0.5 e.g.;
There's also a ViewportOrigin which looks to control where your viewport is within the picture. So, if I set ViewportWidth=0.5 and ViewportOrigin=0.5,0 then I get this;
i.e. the right hand half of the picture.
Ok, I then set ViewportOrigin back to 0,0 and ViewportWidth back to 1.0.
Now...what about all that scrolling and zooming? Well, I must admit that I thought the control just "did it" for you but it appears that you have to do a bit of work.
I'd have liked to have zooming in and out correspond to the mouse wheel but, as far as I know, you can't catch mouse wheel events in Silverlight ( unless you catch them in Javascript and poke them into the .NET world ) so I went for a simple scheme;
- Zoom in by some amount when someone presses the "i" key ( i for in :-) )
- Zoom out by some amount when someone presses the "o" key ( o for out :-))
So I added a key handler to my user control;
<UserControl
x:Class="TestDz.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
KeyDown="OnKeyDown">
<Grid
x:Name="LayoutRoot"
Background="Gray">
<MultiScaleImage
x:Name="msi"
ViewportWidth="1.0"
ViewportOrigin="0,0"
Source="/windowsbackdrops/info.bin" />
</Grid>
</UserControl>
and added code to my code-behind file;
void OnKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.I:
break;
case Key.O:
break;
default:
break;
}
}
Now, at this point I did a little head-scratching as I wasn't quite sure what to do but I noticed that the MultiScaleImage has a function called ZoomAboutLogicalPoint so I thought I'd give that a whirl. It takes a zoomIncrementFactor and it looks like you set this to "larger than 1.0" to zoom in and "between 0 and 1.0" to zoom out.
The function also takes a logical point. There seems to be a function called ElementToLogicalPoint so I figured that probably converts a screen coord to a logical point so I gave this a whirl;
void OnKeyDown(object sender, KeyEventArgs e)
{
double centreX = msi.Width / 2;
// Note - not very sure about this. Then again, not very sure about
// any of it :-)
double centreY = (msi.Width / msi.AspectRatio) / 2;
Point p = msi.ElementToLogicalPoint(new Point(centreX, centreY));
switch (e.Key)
{
case Key.I:
msi.ZoomAboutLogicalPoint(1.1, p.X, p.Y);
break;
case Key.O:
msi.ZoomAboutLogicalPoint(0.9, p.X, p.Y);
break;
default:
break;
}
}
Note, I'm really not very sure about any of that but it seems to zoom about the right point. I thought I'd have a go at panning around a little by handling the arrow keys as well. Note - I think having a fixed factor of 0.1 here is not a great idea;
void OnKeyDown(object sender, KeyEventArgs e)
{
double centreX = msi.Width / 2;
// Note - not very sure about this. Then again, not very sure about
// any of it :-)
double centreY = (msi.Width / msi.AspectRatio) / 2;
Point p = msi.ElementToLogicalPoint(new Point(centreX, centreY));
switch (e.Key)
{
case Key.I:
msi.ZoomAboutLogicalPoint(1.1, p.X, p.Y);
break;
case Key.O:
msi.ZoomAboutLogicalPoint(0.9, p.X, p.Y);
break;
case Key.Left:
msi.ViewportOrigin = new Point(msi.ViewportOrigin.X + 0.1,
msi.ViewportOrigin.Y);
break;
case Key.Right:
msi.ViewportOrigin = new Point(msi.ViewportOrigin.X - 0.1,
msi.ViewportOrigin.Y);
break;
case Key.Up:
msi.ViewportOrigin = new Point(msi.ViewportOrigin.X,
msi.ViewportOrigin.Y - 0.1);
break;
case Key.Down:
msi.ViewportOrigin = new Point(msi.ViewportOrigin.X,
msi.ViewportOrigin.Y + 0.1);
break;
default:
break;
}
}
So...that seems to kind of work.
However, I don't think that I'm actually seeing zooming working in the way that I expect and I suspect that's either;
- I made the image incorrectly in the first place.
- I'm not zooming into it properly.
- Maybe my image just isn't big enough?
When I zoom in, I get a zoom but I don't feel like there are sub-images being downloaded and my SubImages collection is empty.
Anyway - I'll update the post when I know more about it. Perhaps this will help get you started and you can let me know when you've worked it out - I imagine an official tutorial will be along soon.
Posted
Wed, Mar 5 2008 5:46 PM
by
mtaulty