<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Jaime Rodriguez  : deepzoom</title><link>http://blogs.msdn.com/jaimer/archive/tags/deepzoom/default.aspx</link><description>Tags: deepzoom</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Working with Collections in Deep Zoom.</title><link>http://blogs.msdn.com/jaimer/archive/2008/06/23/working-with-collections-in-deep-zoom.aspx</link><pubDate>Tue, 24 Jun 2008 09:29:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8645948</guid><dc:creator>jaimer</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/jaimer/comments/8645948.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jaimer/commentrss.aspx?PostID=8645948</wfw:commentRss><description>&lt;P&gt;In the Deep Zoom run-time, you can load two types of compositions: &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;A single image &lt;STRONG&gt;composition &lt;/STRONG&gt;is when you interact with a single image at run-time.&amp;nbsp; This does not mean you started with a single image, you could start with many images and compose a scene, then you export from Composer and all of the images get 'stitched' into a single composition that you can interact with at run-time.&amp;nbsp; You interact (like zooming, opacity, etc.) with your image by changing the properties of your MultiScaleImage. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;A "&lt;STRONG&gt;Collection of Images&lt;/STRONG&gt;" is when you compose a scene but export it as a collection of images (duh jaime do u get paid by the word? word, word?) &lt;BR&gt;At run-time, you can still interact with each of the individual images in your composition.&amp;nbsp;&amp;nbsp; &lt;BR&gt;The images are exposed via the SubImages collection of your MultiScaleImage.&amp;nbsp;&amp;nbsp; You can still set properties in the MultiScaleImage and these properties will affect all the images in the collection [for example if I Zoom-in to 200% in MSI, that would impact which SubImages are visible] but with collections I also get the benefit of interacting with the SubImages directly. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Collections have a lot more flexibility of course, but I also caution of two tiny concerns: &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;when dealing with collections,&amp;nbsp; you likely end up downloading a few more tiles as you go.&amp;nbsp; Not a huge deal &lt;/LI&gt;
&lt;LI&gt;Your images load independently;&amp;nbsp; this again is not a huge deal unless you have huge discrepancies in size; in that case you will see your small images load earlier than your bigger ones.&amp;nbsp; [To solve this you could play with Opacity] &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;This post is about working with Collections, so let's assume I decided the two issues above are not in play (that is the case for most people).&amp;nbsp; &lt;BR&gt;&lt;BR&gt;To find out what we can do with a MultiScaleSubImage, all we need is to look at the class definition: &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;AspectRatio&lt;/STRONG&gt; - readonly property ==&amp;nbsp; width/height. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Opacity&lt;/STRONG&gt; = self-explains;&amp;nbsp; 0== transparent.&amp;nbsp; 1.0 == Opaque &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;ViewportOrigin&lt;/STRONG&gt; == top-left corner of the image.&amp;nbsp; Stay tuned for a lot more below. This is a really interesting property and 1/3&amp;nbsp; the point of this post &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;ViewportWidth&lt;/STRONG&gt; == width of the area to be displayed.&amp;nbsp; This value is in logical coordinates. For example: &lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;a value of 1 displays the entire image (no zoom), &lt;/LI&gt;
&lt;LI&gt;a value of 0.5 is 200% zoomed in and a value of 0 is completely zoomed (user cannot see the image at all). &lt;/LI&gt;
&lt;LI&gt;A value above 1 is zooming out from the image. For example, a value of 2 means that the image will take up half the size of the MultiScaleImage&amp;nbsp; control area (50% zoom). &lt;BR&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;ZIndex -- self explains;&amp;nbsp; higher numbers are in front of lower ones. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;A few of the less obvious options for dealing with collections are:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Tags &lt;BR&gt;&lt;/STRONG&gt;If you have used Deep Zoom Composer you might have noticed that composer has a property called "Tag" for each image. As of beta2 tag is not exposed via the MultiScaleSubImage.&amp;nbsp; So, how can you get to this Tag? &lt;/P&gt;
&lt;P&gt;The tags are stored in the metadata.xml&amp;nbsp; file generated by Deep Zoom Composer.&amp;nbsp; &lt;BR&gt;You can easily get to this file using WebClient or HttpWebRequest networking APIs in SL2.&amp;nbsp; It is a trivial two step process:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Make call to read XML file.&amp;nbsp; I did it from ImageOpenSucceded to not compete with download traffic for image and to know for sure that when WebClient callback happened I could access the images in the collection. &lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;&lt;BR&gt;void &lt;/SPAN&gt;msi_ImageOpenSucceeded(&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;sender, &lt;SPAN style="COLOR: #2b91af"&gt;RoutedEventArgs &lt;/SPAN&gt;e) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: #2b91af"&gt;WebClient &lt;/SPAN&gt;wc = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;WebClient&lt;/SPAN&gt;(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; wc.DownloadStringCompleted += &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;DownloadStringCompletedEventHandler&lt;/SPAN&gt;(wc_DownloadStringCompleted); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; wc.DownloadStringAsync(&lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Uri&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #a31515"&gt;"GeneratedImages/Metadata.xml"&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;UriKind&lt;/SPAN&gt;.Relative));&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;} &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Then we read the results.&amp;nbsp;&amp;nbsp;&amp;nbsp; The code is below.&amp;nbsp; I used LINQ to XML -that makes it trivial :) &lt;BR&gt;The only thing worth highlighting from the code is the "map" between tags and MultiScaleSubImages.&amp;nbsp; &lt;BR&gt;metadata.xml has a ZOrder, which is a 1-based index of the position of the image in the collection.&amp;nbsp;&amp;nbsp; Despite its name (ZOrder), this has nothing to do with MultiScaleImage.ZIndex . &lt;BR&gt;&lt;BR&gt;The actual collection is 0 based, so we&amp;nbsp; subtract one to the value read from metadata.xml&amp;nbsp;&amp;nbsp;&amp;nbsp; I have put red, highlighted comments on top the two most relevant lines . &lt;/LI&gt;&lt;/OL&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;wc_DownloadStringCompleted(&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;sender, &lt;SPAN style="COLOR: #2b91af"&gt;DownloadStringCompletedEventArgs &lt;/SPAN&gt;e) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;if&lt;/SPAN&gt;(e.Cancelled == &lt;SPAN style="COLOR: blue"&gt;false&lt;/SPAN&gt;&amp;amp;&amp;amp; e.Error == &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;s = e.Result; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: #2b91af"&gt;XDocument &lt;/SPAN&gt;doc = &lt;SPAN style="COLOR: #2b91af"&gt;XDocument&lt;/SPAN&gt;.Parse(s); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;var &lt;/SPAN&gt;images = &lt;SPAN style="COLOR: blue"&gt;from&lt;/SPAN&gt;a &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt;doc.Element(&lt;SPAN style="COLOR: #a31515"&gt;"Metadata"&lt;/SPAN&gt;).Descendants(&lt;SPAN style="COLOR: #a31515"&gt;"Image"&lt;/SPAN&gt;)&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;select&lt;/SPAN&gt;a; &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;foreach &lt;/SPAN&gt;( &lt;SPAN style="COLOR: #2b91af"&gt;XElement &lt;/SPAN&gt;image &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt;images ) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: #2b91af"&gt;CollectionImage &lt;/SPAN&gt;ci = &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CollectionImage &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Height = (&lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt;) image.Element(&lt;SPAN style="COLOR: #a31515"&gt;"Height"&lt;/SPAN&gt;), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Width = (&lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt;) image.Element(&lt;SPAN style="COLOR: #a31515"&gt;"Width"&lt;/SPAN&gt;),&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff0000&gt;&lt;STRONG&gt;//here we read the ZOrder from metadata.xml and subtract one &lt;/STRONG&gt;&lt;/FONT&gt;&lt;BR&gt;&lt;STRONG&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ZOrder = ((&lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt;) image.Element(&lt;SPAN style="COLOR: #a31515"&gt;"ZOrder"&lt;/SPAN&gt;)) -1 , &lt;BR&gt;&lt;/STRONG&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Tag = (&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;) image.Element(&lt;SPAN style="COLOR: #a31515"&gt;"Tag"&lt;/SPAN&gt;), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Location = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Point&lt;/SPAN&gt;{ X = (&lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt;)image.Element(&lt;SPAN style="COLOR: #a31515"&gt;"x"&lt;/SPAN&gt;), Y = (&lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt;) image.Element(&lt;SPAN style="COLOR: #a31515"&gt;"y"&lt;/SPAN&gt;)} &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ; &lt;BR&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff0000&gt;//here we map from the SubImages collection based on the ZOrder we read &lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ci.Image = msi.SubImages[ci.ZOrder]; &lt;BR&gt;&lt;/STRONG&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _images.Add ( ci ) ; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; items.ItemsSource = _images; &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;If you look at the code, I created a CollectionImage which aggregates the stuff from metadata.xml and the corresponding MultiScaleSubImage.&amp;nbsp; &lt;BR&gt;This means I could now filter, or do any thing since the data is merged.&amp;nbsp; &lt;A href="http://blog.kirupa.com/?p=212" target=_blank mce_href="http://blog.kirupa.com/?p=212"&gt;Kirupa has an example of using tags to filter&lt;/A&gt; (so I will stop here on that topic and move to Viewports).&amp;nbsp; &lt;BR&gt;&amp;nbsp; &lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;ViewportOrigin: &lt;BR&gt;&lt;/STRONG&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;ViewportOrigin represents the left(x), top(y) corner of your SubImage relative to the MultiScaleImage control.&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;The surprise (for me at least) is that:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;They are normalized relative to the viewportWidth of the subimage you are dealing with. &lt;/LI&gt;
&lt;LI&gt;Moving towards the right in the horizontal ( X) direction is actually a negative offset, so is moving towards the bottom. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Got it?? OK! you are done.&amp;nbsp;&amp;nbsp; &lt;BR&gt;If you are like me&amp;nbsp; you might want to see a sample.&amp;nbsp; Here are some below:&amp;nbsp; &lt;BR&gt;&lt;/P&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=2 width=800 border=2&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top width=259&gt;&lt;A href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_2.png" target=_blank mce_href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_2.png"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=165 alt=image src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_thumb.png" width=244 border=0 mce_src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_thumb.png"&gt;&lt;/A&gt; &lt;/TD&gt;
&lt;TD class="" vAlign=top width=539&gt;This is a DeepZoom composition w/ two images.&amp;nbsp; &lt;BR&gt;Blue is 1200x800&amp;nbsp; ( Aspect ratio = 1.5 ) &lt;BR&gt;Yellow is 600x400 ( AR = 1.5 ) &lt;BR&gt;&lt;BR&gt;At this point ViewportOrigin = 0,0 for both...&amp;nbsp;&amp;nbsp; Looks good to me. &lt;BR&gt;&lt;BR&gt;It is worth mentioning [if you try to make sense as you go ] that the &lt;BR&gt;ViewportWidth for blue == 1.0&amp;nbsp; [takes the whole width available] &lt;BR&gt;ViewportWidth for yellow == 2.0&amp;nbsp; [takes 1/2 the width available to the control] &lt;BR&gt;&lt;BR&gt;The numbers on the images are "approximations".. if you read a coord of say 900,600 that means it is around there, but not quite exact &lt;BR&gt;&lt;BR&gt;Let's now start changing ViewportOrigin. &lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top width=261&gt;&lt;A href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_4.png" mce_href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_4.png"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=164 alt=image src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_thumb_1.png" width=244 border=0 mce_src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_thumb_1.png"&gt;&lt;/A&gt; &lt;/TD&gt;
&lt;TD class="" vAlign=top width=539&gt;Here I simply changed viewportOrigin in yellow image. &lt;BR&gt;&lt;BR&gt;My first instinct looking at this one would be&amp;nbsp; 1,0 ... [since it is 600 pixels left of 0,0] &lt;BR&gt;I was wrong!! &lt;BR&gt;This is actually ViewportOrigin =&amp;nbsp; -1, 0.. &lt;BR&gt;Remember, when you move an image to right or bottom, the offsets are negative. &lt;BR&gt;&lt;BR&gt;You want to know what would happen if VO was 1,0?? &lt;BR&gt;The demo is at&amp;nbsp; &lt;A title=http://www.cookingwithxaml.com/recipes/DeepZoomCollection/ href="http://www.cookingwithxaml.com/recipes/DeepZoomCollection/default.html" target=_blank mce_href="http://www.cookingwithxaml.com/recipes/DeepZoomCollection/default.html"&gt;http://www.cookingwithxaml.com/recipes/DeepZoomCollection/default.html&lt;/A&gt; &lt;BR&gt;&lt;BR&gt;You can play with ZIndex, Opacity and ViewportOrigin for each image [their values are databound on the grid]. &lt;BR&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top width=262&gt;&lt;A href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_6.png" mce_href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_6.png"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=164 alt=image src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_thumb_2.png" width=244 border=0 mce_src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_thumb_2.png"&gt;&lt;/A&gt; &lt;/TD&gt;
&lt;TD class="" vAlign=top width=539&gt;Having explained that the ViewportOrigins offsets (to right,bottom) are negative numbers. &lt;BR&gt;Can you guess what the offset is for the image to the right? &lt;BR&gt;My guess was ( 0, -1) but then&amp;nbsp; I was wrong again!&amp;nbsp;&amp;nbsp; &lt;BR&gt;The ViewportOrigin here is ( 0, -.66666666666) &lt;BR&gt;Why? &lt;BR&gt;&lt;BR&gt;Because the offsets are relative to the Width and in this case it is 600. &lt;BR&gt;So a viewport of (0,-1) would have been lower in the y axis [instead of at 400, it would be at 600] &lt;BR&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top width=262&gt;&lt;A href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_8.png" mce_href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_8.png"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=163 alt=image src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_thumb_3.png" width=244 border=0 mce_src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_thumb_3.png"&gt;&lt;/A&gt; &lt;/TD&gt;
&lt;TD class="" vAlign=top width=539&gt;This is 0,-1 and exactly what we expected for this one (after reading line above). &lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top width=262&gt;&lt;A href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_10.png" mce_href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_10.png"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=162 alt=image src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_thumb_4.png" width=244 border=0 mce_src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_thumb_4.png"&gt;&lt;/A&gt; &lt;/TD&gt;
&lt;TD class="" vAlign=top width=539&gt;I know you have it by now, but just for fun, this is&amp;nbsp; ( -1.5, -.3333)&amp;nbsp; aka ( 900,200) &lt;BR&gt;Notice how half of our yellow image is clipped.&amp;nbsp; &lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top width=262&gt;&lt;A href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_12.png" mce_href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_12.png"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=165 alt=image src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_thumb_5.png" width=244 border=0 mce_src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/WorkingwithCollectionsinDeepZoom_11AFF/image_thumb_5.png"&gt;&lt;/A&gt; &lt;/TD&gt;
&lt;TD class="" vAlign=top width=539&gt;This is ViewportOrigin ( 0.5, -.3333 ) ... I figured I should show you some thing with a positive value for Viewport Origin...&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;&lt;BR&gt;&amp;nbsp; &lt;BR&gt;Again, you can play with the ugly but hopefully useful sample &lt;A href="http://www.cookingwithxaml.com/recipes/DeepZoomCollection/" target=_blank mce_href="http://www.cookingwithxaml.com/recipes/DeepZoomCollection/"&gt;here&lt;/A&gt;..&amp;nbsp; &lt;BR&gt;Just change the ViewportOrigin, or any other property and see what happens. &lt;BR&gt;You can use the same sample to play with Opacity, ZIndex&amp;nbsp; and ViewportWidth..&amp;nbsp;&amp;nbsp; this will show you the flexibility in collections. &lt;BR&gt;Don't get tricky with the values as there is no validation. &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Mapping SubImages to Element Coordinates &lt;/STRONG&gt;&lt;BR&gt;Now that we understand ViewportWidth and ViewportOrigin,&amp;nbsp; we can map from logical coordinates to element coordinates so we can put overlays on our MultiScaleImage.&amp;nbsp; Or do hit testing or any thing similar. &lt;BR&gt;&lt;/P&gt;
&lt;P&gt;What I did is put a small pink rectangle in the page and I am going to listen to MouseMove on the MultiScaleImage and then do kind of a "hit testing" to see which Image I am over.&amp;nbsp; I used ZIndex to select only the single image on the front. If you did not use ZIndex you can select multiple. &lt;BR&gt;&lt;BR&gt;So, what does the map look like??&amp;nbsp;&amp;nbsp; The whole code is below commented in detail..&amp;nbsp; I hope that makes it easiest to explain -instead of my rambles-. &lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;Gets a rectangle representing the top-most image that the mouse is over
&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name="elementPoint"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;Mouse Position, in Element Coordinates&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;&amp;lt;/param&amp;gt;
/// &amp;lt;returns&amp;gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;Rectangle reprsenting Element Coordinates for the image or 0,0,0,0 if not over an image&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;&amp;lt;/returns&amp;gt;
&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Rect &lt;/SPAN&gt;SubImageHitTestUsingElement(&lt;SPAN style="COLOR: #2b91af"&gt;Point &lt;/SPAN&gt;elementPoint)
{
    &lt;SPAN style="COLOR: #2b91af"&gt;Rect &lt;/SPAN&gt;resultRect = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Rect&lt;/SPAN&gt;(0, 0, 0, 0);
    &lt;SPAN style="COLOR: blue"&gt;int &lt;/SPAN&gt;zIndex = 0;

    &lt;SPAN style="COLOR: green"&gt;// We loop through all our images. 
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;for &lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;int &lt;/SPAN&gt;i = 0; i &amp;lt; _images.Count; i++)
    {
        &lt;SPAN style="COLOR: blue"&gt;try
        &lt;/SPAN&gt;{
            &lt;SPAN style="COLOR: green"&gt;// Selct our MSSI. 
            &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;MultiScaleSubImage &lt;/SPAN&gt;subImage = _images[i].Image;

            &lt;SPAN style="COLOR: green"&gt;// NOTICE the scale is a mutliplication of the size of our image (1 / subImage.ViewportWidth)
            // and the current Zoom level ( 1 / msi.ViewportWidth) 
            &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;double &lt;/SPAN&gt;scaleBy = 1 / subImage.ViewportWidth * 1 / msi.ViewportWidth;

            &lt;SPAN style="COLOR: green"&gt;// The two lines below convert our image size us from Logical to Element Coords
            // Notice that for Height, we must take into account Aspect ratio. 
            &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;double &lt;/SPAN&gt;width = scaleBy * &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.msi.ActualWidth;
            &lt;SPAN style="COLOR: blue"&gt;double &lt;/SPAN&gt;height = (scaleBy * &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.msi.ActualWidth * (1 / subImage.AspectRatio));

            &lt;SPAN style="COLOR: green"&gt;// Now we convert our viewportorigin  (logical coords) to Element Coords
            // Reminder, this is top-left ..  Notice that we multiply by -1 since 
            // we saw the negative math for Viewport Origin. 
            &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Point &lt;/SPAN&gt;p = msi.LogicalToElementPoint(
                &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Point&lt;/SPAN&gt;(
                     -subImage.ViewportOrigin.X * 1 / subImage.ViewportWidth,
                    - subImage.ViewportOrigin.Y * 1 / subImage.ViewportWidth));
             
            &lt;SPAN style="COLOR: green"&gt;// Now we create a Rectangle in Element Coords. 
            &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Rect &lt;/SPAN&gt;subImageRect = &lt;SPAN style="COLOR: blue"&gt;new
                &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Rect&lt;/SPAN&gt;(p.X, p.Y, width, height);

            &lt;SPAN style="COLOR: green"&gt;// here we hitTest, using Contains.. 
            // and we keep track of the front-most element only..                    
            &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(subImageRect.Contains(elementPoint))
            {
                &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(subImage.ZIndex &amp;gt;= zIndex)
                {

                    zIndex = subImage.ZIndex;
                    resultRect = subImageRect;                            
                }
            }
        }
        &lt;SPAN style="COLOR: blue"&gt;catch &lt;/SPAN&gt;(&lt;SPAN style="COLOR: #2b91af"&gt;Exception &lt;/SPAN&gt;ex)
        {
            System.Diagnostics.&lt;SPAN style="COLOR: #2b91af"&gt;Debug&lt;/SPAN&gt;.WriteLine(ex.Message); 
        } 
    }
    System.Diagnostics.&lt;SPAN style="COLOR: #2b91af"&gt;Debug&lt;/SPAN&gt;.WriteLine(&lt;SPAN style="COLOR: #a31515"&gt;"Done"&lt;/SPAN&gt;);
    &lt;SPAN style="COLOR: blue"&gt;return &lt;/SPAN&gt;resultRect;
} &lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;&lt;BR&gt;I used Element Coords because that is what I was after. If you want logical coords, it should be easy from code above..&amp;nbsp; &lt;BR&gt;Just convert the point to Logical, do the scaling for zoom and hittest against a logical rect... &lt;BR&gt;&lt;BR&gt;Fair enough???&amp;nbsp;&amp;nbsp; The source is [you guessed it] at &lt;A href="http://cid-123ec1ed6c72a14a.skydrive.live.com/self.aspx/Public/DeepZoomCollections.zip" mce_href="http://cid-123ec1ed6c72a14a.skydrive.live.com/self.aspx/Public/DeepZoomCollections.zip"&gt;Skydrive&lt;/A&gt;. &lt;BR&gt;&lt;/P&gt;
&lt;P&gt;You can see a few tiny issues I did not care much for: &lt;BR&gt;1) My math is rounded so some times you see the 'Rectangle' I created be slightly off (adding some extra pixels should do fine) ... &lt;BR&gt;2) I did the recalculation for rectangle only on mouse move..&amp;nbsp; and I did not do it on Pan... so if you Zoom using Wheel or you pan, it will take for you to move the mouse one more time in order for Rectangle overlay to update. &lt;/P&gt;
&lt;P&gt;That is my part!!&amp;nbsp; Now it is up to you to build some thing really cool using real images and hittesting.. &lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8645948" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jaimer/archive/tags/silverlight/default.aspx">silverlight</category><category domain="http://blogs.msdn.com/jaimer/archive/tags/deepzoom/default.aspx">deepzoom</category></item><item><title>A deepzoom primer ( explained and coded)..</title><link>http://blogs.msdn.com/jaimer/archive/2008/03/31/a-deepzoom-primer-explained-and-coded.aspx</link><pubDate>Tue, 01 Apr 2008 08:56:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8347451</guid><dc:creator>jaimer</dc:creator><slash:comments>18</slash:comments><comments>http://blogs.msdn.com/jaimer/comments/8347451.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jaimer/commentrss.aspx?PostID=8347451</wfw:commentRss><description>&lt;P&gt;I had to learn DeepZoom recently and along the way I put together some handy notes .. below are the notes organized in a near step-by-step explanation format.&amp;nbsp; This is a very long post, but I hope it has useful insights for any one wanting to do deepzoom so I recommend you read it all.&amp;nbsp; If you must skip, then the outline will help you.&amp;nbsp; imo, part 3 and 5 are the good stuff.&amp;nbsp; &lt;BR&gt;&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Part 1 – The history and brief explanation on how DeepZoom works. &lt;/P&gt;
&lt;P&gt;Part 2 – Constructing a DeepZoom image using Image Composer &lt;/P&gt;
&lt;P&gt;Part 3 – Introduction to the DeepZoom object model – goes way beyond the docs I hope &lt;/P&gt;
&lt;P&gt;Part 4 – Coding a deepZoom ‘host’ user control with Pan &amp;amp; Zoom &lt;/P&gt;
&lt;P&gt;Part 4.1 – Adding a few extra features to our User Control &lt;/P&gt;
&lt;P&gt;Part 5 – Lessons learned on the code, documenting the gotchas&amp;nbsp; **must read even if you know Deep Zoom already &lt;/P&gt;
&lt;P&gt;Part 6 – Give me the code, just a zip file w/ the goodies&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Part 7 – Show me the outcome; what did we build? &lt;/P&gt;
&lt;H1&gt;Part 1 – The History &amp;amp; Math behind DeepZoom&lt;/H1&gt;
&lt;P&gt;A lot of people equate DeepZoom to SeaDragon – they assume SeaDragon was the code name and DeepZoom is the marketing name-. This assumption is not quite right (unless you equate your engine to your car model).&amp;nbsp; &lt;A href="http://labs.live.com/Seadragon.aspx" mce_href="http://labs.live.com/Seadragon.aspx"&gt;Seadragon&lt;/A&gt; is an incubation project resulting from the acquisition of Seadragon Software; the Seadragon team is part of the Live organization and are working on several projects (like Photosynth). DeepZoom is an implementation that exposes some of the SeaDragon technology to Silverlight. &lt;/P&gt;
&lt;P&gt;DeepZoom provides the ability to smoothly present and navigate large amounts of visual information (images) regardless of the size of the size of the data, and optimizing the bandwidth available to download it.&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=2 width="100%" border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top&gt;
&lt;P&gt;&lt;STRONG&gt;How does DeepZoom work? &lt;BR&gt;&lt;/STRONG&gt;&lt;BR&gt;DeepZoom accomplishes its goal by partitioning an image (or a composition of images) into tiles.&amp;nbsp; While tiling the image, the composer also creates a pyramid of lower resolution tiles for the original composition.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;The image to the right shows you what a pyramid; the original image is lowest in the pyramid, notice how it is tiled into smaller images, also notice the pyramid creates lower resolution images (also tiled).&amp;nbsp;&amp;nbsp; A few of the docs I read said the tiles are 256x256, but from peeking through the files generated by the composer I am not convinced; I do know from reading through the internal stuff that there is some heavy math involved here, so I trust they tile for right size :). &lt;/P&gt;
&lt;P&gt;All of this tiling is performed at design-time and gets accomplished using the DeepZoom composer. &lt;/P&gt;
&lt;P&gt;At run-time a MultiScaleImage downloads a lower resolution tile of the image first and downloads the other images on demand (as you pan or zoom); DeepZoom make sure the transitions from lower to higher res images are smooth and seamless.&amp;nbsp; &lt;/P&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top width=380&gt;&lt;A href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/PYRPSD_3.jpg" mce_href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/PYRPSD_3.jpg"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=304 alt=PYRPSD src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/PYRPSD_thumb.jpg" width=404 border=0 mce_src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/PYRPSD_thumb.jpg"&gt;&lt;/A&gt; &lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;Given all this, &lt;STRONG&gt;how is Deepzoom different than say a ScaleTransform (for zoom) on a high resolution image? &lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;With a ScaleTransform, usually you would download the whole high res image at once; this delays how quickly the end user gets to see the image when the page or application loads.&amp;nbsp; Some times people apply a trick where you use different resolutions images, since you are not tiled you will likely end up downloading several big images (consuming more network bandwidth) or the download time will continue to be high if the initial downloaded image is not small enough, also the transitions from low to higher res are going to be more noticeable unless your write the transitions yourself. &lt;/P&gt;
&lt;P&gt;DeepZoom and its tiling make it possible to see bits quicker and can optimize for bandwidth.&amp;nbsp; In the worst case scenario where some one looked at every single one of the tiles at the highest resolution, DeepZoom would have an extra overhead of 33% compared to downloading the single highest resolution image at once, but this ‘worst case’ scenario is almost never hit, most of the time DeepZoom can save you from downloading too much.&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Another feature in DeepZoom is its ability to create ‘collections’ from the composite image.&amp;nbsp; This provides you the ability to compose a scene ( group of images ), optimize them for speed &amp;amp; download, but still maintain the ‘autonomy’ and identity of the image, you can programmatically manipulate (or position) these images from within the DeepZoom collection (more on collections in part 4). &lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;/P&gt;
&lt;H1&gt;Part 2 – Constructing a DeepZoom Image using DeepZoom composer&amp;nbsp; &lt;/H1&gt;
&lt;OL&gt;
&lt;LI&gt;We begin by downloading the "DeepZoom composer" from &lt;A href="http://download.microsoft.com/download/b/3/5/b352676b-9ea1-4ac8-904f-8d14aa60df84/DeepZoomComposer.msi" mce_href="http://download.microsoft.com/download/b/3/5/b352676b-9ea1-4ac8-904f-8d14aa60df84/DeepZoomComposer.msi"&gt;Microsoft Downloads&lt;/A&gt;. &lt;BR&gt;If you want a great reference for the tool, try the &lt;A href="http://blogs.msdn.com/expression/archive/2008/03/05/deep-zoom-composer-user-guide.aspx" mce_href="http://blogs.msdn.com/expression/archive/2008/03/05/deep-zoom-composer-user-guide.aspx"&gt;DeepZoom Composer guide&lt;/A&gt;. In the steps below, I am going to keep it to the minimum steps needed and some of the gotchas when using the tool. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;After installing the DeepZoom Composer, we launch it.&amp;nbsp; &lt;BR&gt;Trivia facts: Composer is a WPF application, like most of the other Expression products. Also, codename was Mermaid (you can see this from the export window). &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Under the File Menu, select "New Project" 
&lt;TABLE class="" cellSpacing=0 cellPadding=2 width=675 border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top width=396&gt;
&lt;OL&gt;
&lt;OL&gt;
&lt;LI&gt;Select a location to store the project. &lt;BR&gt;I recommend some thing with a short path like c:\users\jaimer\. The composer has some usability issues that make working with long paths a little hard; and the composer will append to your path later when you export. &lt;/LI&gt;
&lt;LI&gt;I called it "EasterEggHunt" as that is what my project will be. &lt;/LI&gt;&lt;/OL&gt;&lt;/OL&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top width=277&gt;&lt;A href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_2.png" mce_href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_2.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=147 alt=image src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_thumb.png" width=244 border=0 mce_src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_thumb.png"&gt;&lt;/A&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/LI&gt;
&lt;LI&gt;Now click "Add Image" to import a few images. &lt;BR&gt;You can import multiple images at once.&amp;nbsp; In my case, I am importing 3 images: bummysmall.jpg, eggs.jpg, and world2.jpg). These are in the inputimages directory if your are following along with the source. &lt;BR&gt;&lt;A href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_4.png" mce_href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_4.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=445 alt=image src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_thumb_1.png" width=624 border=0 mce_src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_thumb_1.png"&gt;&lt;/A&gt;&amp;nbsp; &lt;BR&gt;This added all the images we are going to use in the composer.&amp;nbsp; All images must be added at design-time. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Click "Compose"&amp;nbsp; on the Center toolbar to compose the DeepZoom image. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Double click the world image to add it to the 'stage' or design surface. &lt;/LI&gt;
&lt;LI&gt;Click Fit To Screen to maximize our space. &lt;/LI&gt;
&lt;LI&gt;Click on the eggs image&amp;nbsp; to add it to the stage. &lt;/LI&gt;
&lt;LI&gt;Zoom many times into the image at a place where you want to drop some easter eggs. 
&lt;OL&gt;
&lt;LI&gt;Hint:&amp;nbsp; the Usual short cuts of Ctrl+ and Ctrl-&amp;nbsp; do work for zooming. Unfortunately Pan(h) and Select(v) don't work. &lt;/LI&gt;&lt;/OL&gt;&lt;/LI&gt;
&lt;LI&gt;Shrink the easter eggs into a small size -- don't worry, with DeepZoom we will be able to Zoom a lot at run-time to find them and see them. &lt;/LI&gt;
&lt;LI&gt;Drop the easter eggs where you want to. He is an example of mine, I dropped them in Mexico. Notice I am quite zoomed into the map and the eggs are small. &lt;BR&gt;&lt;BR&gt;&lt;A href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_6.png" mce_href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_6.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=388 alt=image src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_thumb_2.png" width=583 border=0 mce_src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_thumb_2.png"&gt;&lt;/A&gt;&amp;nbsp; &lt;BR&gt;&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Repeat the steps in 11 for the bunny picture.&amp;nbsp; In my case,&amp;nbsp; I did it in Seattle area. &lt;BR&gt;Note: unfortunately I could not figure how to drag same image twice into stage area.&amp;nbsp; The work around I used is to make a copy of the image with different name, and add it to the image gallery ( Step 4). &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Click Ctrl-0 to see our DeepZoom Image with out the zooms.&amp;nbsp; You sized it right if you can't easily see the eggs and bunny in the map. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;CLick "Export" in the main toolbar.&amp;nbsp; &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Here we enter the settings for output. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Leave the "generate collection" unchecked for now. &lt;BR&gt;What Generate Collection does is exports the DeepZoom Image with metadata and at run-time the images can be accessed via the MultiScaleImage.SubImages&amp;nbsp; property.&amp;nbsp;&amp;nbsp; If you can get to these images, you can move them around the composed image ( for layout ) you can also tweak their Opacity. &lt;BR&gt;The reason I am leaving them unchecked is beause there seems to be a bug (at least on my machine) where if I click Generate Collections my images at run-time show at an offset of where they are supposed to be.&amp;nbsp;&amp;nbsp; I have reported it to the DZC team and they are investigating. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Enter a Name&amp;nbsp; ( "Easter" on the export Dialog). &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;I leave the Output path untouched. &lt;BR&gt;This is where having entered a short path in Step 2 above would pay up because their Path dialog does not Wrap and it is fairly small. [Kirupa already said this is improving for next version]. If you opt to change the path, be attentive when you export again, it seems to reset to its default value. &lt;BR&gt;&lt;BR&gt;&lt;A href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_8.png" mce_href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_8.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=340 alt=image src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_thumb_3.png" width=589 border=0 mce_src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_thumb_3.png"&gt;&lt;/A&gt; &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Now, assuming your output looks similar to mine above, (Create Collection unchecked) Click Export and we are done when it says Export Completed. &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;&lt;BR&gt;&lt;/P&gt;
&lt;H1&gt;Part 3 - DeepZoom Object Model &lt;BR&gt;&lt;/H1&gt;
&lt;P&gt;Once you have a DeepZoom image, you will need an instance of the MultiScaleImage class in your silverlight application to load that image.&amp;nbsp; Instantiating the MultiScaleImage class can be done from XAML &lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;MultiScaleImage &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;x&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Name&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="DeepZoom" &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Source&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="easter/info.bin" /&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;or from code: &lt;/P&gt;
&lt;P&gt;MultiScaleImage DeepZoom = new MultiScaleImage () ; &lt;/P&gt;
&lt;P&gt;DeepZoom.Source = new Uri ( “easter/info.bin”) ; &lt;/P&gt;
&lt;P&gt;Before&amp;nbsp; going through the DeepZoom API it makes sense to understand the terminology used: &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Logical Coordinates – is a normalized value (0 to 1) representing a coordinate in the image itself (not the control) &lt;/LI&gt;
&lt;LI&gt;Element Coordinates – is the actual control coordinates. For example in a MultiScaleImage of Width=800, Height =400, when the mouse is at the center, the element coordinates are 400,400.&amp;nbsp; These coordinates are not normalized. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Now, we navigate through the interesting properties and methods in MultiScaleImage&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Source – refers to the Image source; usually info.bin when not using collections or items.bin&amp;nbsp; if using collections.&amp;nbsp; &lt;/LI&gt;
&lt;LI&gt;SubImages – when using collections, this is a reference to all the images in a composed DeepZoom Image. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;ViewportWidth – Specifies the width of the parts of the image to be displayed. The value is in Logical coordinates. &lt;BR&gt;For example:&amp;nbsp; &lt;BR&gt;Width=2 means image is zoomed out and only takes half the space available.&amp;nbsp; &lt;BR&gt;To zoom in, a viewport &amp;lt; 1 is required.&amp;nbsp; ViewportWidth of 0.5 is a 200% zoom. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;ViewportOrigin – the Top,Left corner for the parts of the image to be displayed.&amp;nbsp; This is returned in Logical coordinates.&amp;nbsp; For example, imagine I am panning by 10% each time and I pan twice to the right while zoomed in at 100% (so no zoom), my ViewportOrigin.X will be 0.2. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;UseSprings – gets or set whether DeepZoom animates the transitions ( like ZoomAboutLogicalPoint, updates to ViewportOrigin, etc. ). &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;The interesting methods are: &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;ElementToLogicalPoint – takes a coordinate of the control, and gives you a logical ( normalized coordinate). &lt;BR&gt;For example, mouse at Center (400,400) with ViewportWidth=1 and you call ElementToLogical ( ) will return (0.5, 0.5) &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;LogicalToElementPoint – takes a logical coordinate (normalized) and returns a point in the MultiScaleImage control where that logical point corresponds to. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;ZoomAboutLogicalPoint – implements the Zoom.&amp;nbsp; The two parameters are the new zoom multiplier - as an increment from current zoom factor in the image - and the Logical point at which to zoom around.&amp;nbsp; &lt;BR&gt;Example of the incremental zoom would be to ZoomAboutLogicalPoint&amp;nbsp; ( 1.5, 0.5, 0.5) .. I will be zoomed in to 1.5 times;&amp;nbsp; if I repeat this operation with same values I am zoomed in at 1.5 * 1.5&amp;nbsp; which is 2.25 times from size where I started. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;In my opinion, surprisingly missing from the API were: &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;The original width and height of the DeepZoomImage&amp;nbsp; (so that I can translate normalized logical coords to physical on the image). &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Zoom – to tell you the current total Zoom level; this one you can get around by keeping track of any zooms you implement. Another possible workaround is that Zoom appears to be 1/ViewportWidth; I can’t think of the scenario where this does not hold, if there is please let me know and again just keep track of your zooms if that happens. &lt;/LI&gt;&lt;/UL&gt;
&lt;H1&gt;Part 4 – Coding a&amp;nbsp; DeepZoom Host User Control &lt;/H1&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;P&gt;The goal here is to code a sample&amp;nbsp; reusable control just to illustrate the points; along the way we will of course implement enough features for our Easter Egg Hunt.&amp;nbsp; [Update: Sorry about belatedness, I started this on 3/22 but had a trip that prevented me from playing around, so I am late from easter] &lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Inside Visual Studio 2008, create a new Silverlight Application; I called it DeepZoomSample. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Build the application so the Clientbin directory is created. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Copy the output from the DeepZoom Composer to the Clientbin directory of our Silverlight application. &lt;BR&gt;In my case, I called the output “Easter” so I can go into the output directory from composer and just copy that whole directory to my Silverlight Application’s ClientBin. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Now that we have our image, we can edit the XAML in Page.Xaml, to show the image. &lt;BR&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;UserControl &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;x&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Class&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="DeepZoomSample.Page"
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;xmlns&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="http://schemas.microsoft.com/client/2007" 
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;xmlns&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;x&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="http://schemas.microsoft.com/winfx/2006/xaml" 
    &amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Grid &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;x&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Name&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="LayoutRoot" &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Background&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="White"&amp;gt;
        &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;MultiScaleImage &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;x&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Name&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="DeepZoom" &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Source&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="easter/info.bin" /&amp;gt; 
    &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Grid&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;
&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;UserControl&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;If you run the application now, you will see the image loads&amp;nbsp; but there is no functionality: zoom and pan have not been implemented.&amp;nbsp; &lt;BR&gt;For zoom, we need to use the mouse wheel, but Silverlight has no native support for it. A good work around is to use Peter Blois’ MouseWheelHelper. This class uses HTML Bridge to listen to the mouse wheel event in the browser and exposes the events to managed code. &lt;BR&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;Add a new code file to your project, I called it MouseWheelHelper. &lt;/LI&gt;
&lt;LI&gt;Copy Peter’s code below into the MouseWheelHelper file. &lt;BR&gt;
&lt;DIV style="OVERFLOW: auto; HEIGHT: 300px"&gt;
&lt;P&gt;using System; &lt;BR&gt;using System.Windows; &lt;BR&gt;using System.Windows.Controls; &lt;BR&gt;using System.Windows.Documents; &lt;BR&gt;using System.Windows.Ink; &lt;BR&gt;using System.Windows.Input; &lt;BR&gt;using System.Windows.Media; &lt;BR&gt;using System.Windows.Media.Animation; &lt;BR&gt;using System.Windows.Shapes; &lt;BR&gt;using System.Windows.Browser; &lt;/P&gt;
&lt;P&gt;namespace DeepZoomSample &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // this code came from Peter Blois,&amp;nbsp; &lt;A href="http://www.blois.us/blog" mce_href="http://www.blois.us/blog"&gt;http://www.blois.us/blog&lt;/A&gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Code ported by Pete blois from Javascript version at &lt;A href="http://adomas.org/javascript-mouse-wheel/" mce_href="http://adomas.org/javascript-mouse-wheel/"&gt;http://adomas.org/javascript-mouse-wheel/&lt;/A&gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public class MouseWheelEventArgs : EventArgs &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private double delta; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private bool handled = false; &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public MouseWheelEventArgs(double delta) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.delta = delta; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public double Delta &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return this.delta; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Use handled to prevent the default browser behavior! &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public bool Handled &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return this.handled; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set { this.handled = value; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public class MouseWheelHelper &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public event EventHandler&amp;lt;MouseWheelEventArgs&amp;gt; Moved; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static Worker worker; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private bool isMouseOver = false; &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public MouseWheelHelper(FrameworkElement element) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (MouseWheelHelper.worker == null) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MouseWheelHelper.worker = new Worker(); &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MouseWheelHelper.worker.Moved += this.HandleMouseWheel; &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; element.MouseEnter += this.HandleMouseEnter; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; element.MouseLeave += this.HandleMouseLeave; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; element.MouseMove += this.HandleMouseMove; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private void HandleMouseWheel(object sender, MouseWheelEventArgs args) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (this.isMouseOver) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.Moved(this, args); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private void HandleMouseEnter(object sender, EventArgs e) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.isMouseOver = true; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private void HandleMouseLeave(object sender, EventArgs e) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.isMouseOver = false; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private void HandleMouseMove(object sender, EventArgs e) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.isMouseOver = true; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private class Worker &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public event EventHandler&amp;lt;MouseWheelEventArgs&amp;gt; Moved; &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Worker() &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (HtmlPage.IsEnabled) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; HtmlPage.Window.AttachEvent("DOMMouseScroll", this.HandleMouseWheel); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; HtmlPage.Window.AttachEvent("onmousewheel", this.HandleMouseWheel); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; HtmlPage.Document.AttachEvent("onmousewheel", this.HandleMouseWheel); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private void HandleMouseWheel(object sender, HtmlEventArgs args) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; double delta = 0; &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ScriptObject eventObj = args.EventObject; &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (eventObj.GetProperty("wheelDelta") != null) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; delta = ((double)eventObj.GetProperty("wheelDelta")) / 120; &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (HtmlPage.Window.GetProperty("opera") != null) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; delta = -delta; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else if (eventObj.GetProperty("detail") != null) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; delta = -((double)eventObj.GetProperty("detail")) / 3; &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (HtmlPage.BrowserInformation.UserAgent.IndexOf("Macintosh") != -1) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; delta = delta * 3; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (delta != 0 &amp;amp;&amp;amp; this.Moved != null) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MouseWheelEventArgs wheelArgs = new MouseWheelEventArgs(delta); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.Moved(this, wheelArgs); &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (wheelArgs.Handled) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; args.PreventDefault(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;}&lt;/P&gt;&lt;BR&gt;&lt;/DIV&gt;&lt;BR&gt;&lt;BR&gt;MouseWheelHelper fires a Moved Event whenever the Wheel moves. The EventArgs is a MouseWheelEventArgs, which has the delta property. Delta is a normalized property (0 to 1), for now all we look at is whether it is greater than 0 or not. &lt;BR&gt;If Delta is greater than 0, then the wheel has rotated away from the user; if Delta is a negative number, then the wheel has rotated toward the user. &lt;BR&gt;&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Before we handle the Moved event, let’s add a ZoomFactor property to our control, this will be the increment/decrement on a wheel operation. The default value is 1.3, which is a 30% increment.&amp;nbsp; Nothing scientific behind this number, I am pretty much just ‘copying’ what I see every other sample do. I think the number works OK. &lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;&lt;FONT face=Verdana color=#333333&gt; &lt;/FONT&gt;protected double &lt;/SPAN&gt;_defaultZoom = 1.3; 
       &lt;SPAN style="COLOR: blue"&gt;public double &lt;/SPAN&gt;DefaultZoomFactor
       {
           &lt;SPAN style="COLOR: blue"&gt;get
           &lt;/SPAN&gt;{
               &lt;SPAN style="COLOR: blue"&gt;return &lt;/SPAN&gt;_defaultZoom; 
           }
           &lt;SPAN style="COLOR: blue"&gt;set
           &lt;/SPAN&gt;{
               _defaultZoom = &lt;SPAN style="COLOR: blue"&gt;value&lt;/SPAN&gt;; 
           } 
       }&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;We also add a CurrentTotalZoom property, this will be a cached version of overall zoom level (since we can’t query this from the MultiScaleImage API.&amp;nbsp; I also added a MaxZoomIn and MaxZoomOut to prevent the image from going too far in (is there such a thing?) or too far out. Too Far out did matter as the image can disapper if you go too far.&amp;nbsp; In my case I picked my Maximum values arbitrarily. &lt;BR&gt;
&lt;DIV style="OVERFLOW: auto; HEIGHT: 300px"&gt;
&lt;P&gt;&lt;BR&gt;private double _currentTotalZoom = 1.0; &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public double CurrentTotalZoom &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return _currentTotalZoom; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set { _currentTotalZoom = value; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private double _maxZoomIn = 5000; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected double MaxZoomIn &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return _maxZoomIn; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set { _maxZoomIn = value; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private double _maxZoomOut = 0.001; &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected double MaxZoomOut &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return _maxZoomOut; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set { _maxZoomOut = value; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/P&gt;&lt;/DIV&gt;&lt;PRE class=code&gt;&lt;FONT color=#0000ff&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;Now, we can add a DoZoom function to our class, this will be called when there is a Zoom operation.&amp;nbsp;&amp;nbsp; The parameters for it are: the new Zoom level RELATIVE to where the image is at,&amp;nbsp; and&amp;nbsp; a point in Element Coordinates since most likely we will be zooming around the mouse, and we get Element coordiantes out of that. &lt;PRE class=code&gt;&lt;FONT color=#808080&gt;&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;summary&amp;gt;
      /// &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;Performs a Zoom operation relative to where Image is at. 
      &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;/// &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;Example, call DoZoom twice with a Zoom of 1.25 will lead to an image that is zoomed at 
      &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;/// &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;1.25 after first time and ( 1.25 * 1.25 for second time, which is a 1.56
      &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;/summary&amp;gt;
      /// &amp;lt;param name="relativeZoom"&amp;gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;new zoom level; this is a RELATIVE value not absolute.&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;&amp;lt;/param&amp;gt;
      /// &amp;lt;param name="elementPoint"&amp;gt;&amp;lt;/param&amp;gt;
      &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;DoZoom(&lt;SPAN style="COLOR: blue"&gt;double &lt;/SPAN&gt;relativeZoom , &lt;SPAN style="COLOR: #2b91af"&gt;Point &lt;/SPAN&gt;elementPoint)
      {
          &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(  _currentTotalZoom * relativeZoom &amp;lt; MaxZoomOut ||
                _currentTotalZoom * relativeZoom &amp;gt; MaxZoomIn) 
              &lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt;; 
 
          &lt;SPAN style="COLOR: #2b91af"&gt;Point &lt;/SPAN&gt;p = DeepZoom.ElementToLogicalPoint(elementPoint);
          DeepZoom.ZoomAboutLogicalPoint(relativeZoom, p.X, p.Y);
          &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.Zoom = relativeZoom;
          _currentTotalZoom *= relativeZoom; 
                } &lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;Now we are ready to handle the MouseWheelHelper.Moved event.&amp;nbsp;&amp;nbsp; We will do it in three parts:&amp;nbsp; 
&lt;OL&gt;
&lt;LI&gt;We will subscribe to MouseMove event in the MultiScaleImage, so we can keep track of where the mouse is; we need this because MouseWheelHelper.Moved does not give us a MousePosition, and there is no way to query MousePosition in Silverlight2 outside of a Mouse EventHandler. &lt;BR&gt;&lt;BR&gt;// inside the Loaded event for the user control &lt;BR&gt;//{ &lt;BR&gt;DeepZoom.MouseMove += &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;MouseEventHandler&lt;/SPAN&gt;(DeepZoom_MouseMove); &lt;BR&gt;_lastMousePosition = new Point ( DeepZoom.ActualWidth /2 , DeepZoom.ActualHeight /2); &lt;BR&gt;//} &lt;BR&gt;&amp;nbsp; &lt;BR&gt;protected Point _lastMousePosition; &lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;DeepZoom_MouseMove(&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;sender, &lt;SPAN style="COLOR: #2b91af"&gt;MouseEventArgs &lt;/SPAN&gt;e) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _lastMousePosition = e.GetPosition(DeepZoom); &lt;BR&gt;} &lt;BR&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;Now we instantiate a MouseWheelHelper and subscribe to Moved event &lt;BR&gt;&lt;BR&gt;// inside the Loaded Event for UserControl &lt;BR&gt;&lt;SPAN style="COLOR: #2b91af"&gt;MouseWheelHelper &lt;/SPAN&gt;mousewheelhelper = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;MouseWheelHelper&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;); &lt;BR&gt;mousewheelhelper.Moved += &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;EventHandler&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;MouseWheelEventArgs&lt;/SPAN&gt;&amp;gt;(OnMouseWheelMoved); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;We add the OnMouseWheelMoved function to the UserControl class.. &lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;OnMouseWheelMoved(&lt;SPAN style="COLOR: blue"&gt;object &lt;/SPAN&gt;sender, &lt;SPAN style="COLOR: #2b91af"&gt;MouseWheelEventArgs &lt;/SPAN&gt;e)
{   
&lt;SPAN style="COLOR: green"&gt;   // e.Delta &amp;gt; 0 == wheel moved away, zoom in 
&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;   if &lt;/SPAN&gt;(e.Delta &amp;gt; 0)
   {
      DoZoom( DefaultZoomFactor, _lastMousePosition);
   }
&lt;SPAN style="COLOR: blue"&gt;   else
&lt;/SPAN&gt;   {
&lt;SPAN style="COLOR: green"&gt;      // Zoom out 
&lt;/SPAN&gt;      DoZoom( 1/ DefaultZoomFactor, _lastMousePosition);
   } 
}&lt;BR&gt; &lt;BR&gt;&lt;/PRE&gt;&lt;/LI&gt;
&lt;LI&gt;NOTE: If you compare the source above with the code in the sample source, they are slightly different. &lt;BR&gt;In the sample source there is two approaches to handling Zoom, and there is a boolean flag called _useRelatives that controls this. if you set _useRelatives to true, it will zoom based in relation to a last zoom; I think this makes it more complicated but for some reason most samples I have seen of DeepZoom use this calculation.&amp;nbsp; I think the behavior is the same than the approach I took, but the math is simpler with the approach in the steps above.&amp;nbsp;&amp;nbsp; I did add both in case I find later that there was a scenario addressed by the _useRelatives approach. &lt;BR&gt;&lt;BR&gt;&lt;/LI&gt;&lt;/OL&gt;&lt;/LI&gt;
&lt;LI&gt;At this point we should be able to run the application and get Zoom to work (in and out) around the mouse location.&amp;nbsp; Compile the app and run it to make sure we are making progress. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;To Pan, we need to detect the MouseLeftButtonDown and MouseLeftButtonUp,&amp;nbsp; the assumption is we will pan when the mouse is down, and pan in the direction of the Mouse movement and then stop panning when the mouse is up. &lt;BR&gt;
&lt;OL&gt;
&lt;LI&gt;Let’s add a handler for MouseLeftButtonDown, we add the listener in the UserControl’s Loaded event.&amp;nbsp; This handler will set a variable called _isDragging&amp;nbsp; to flag that the mouse is down; we will use this flag on the MouseMove handler. &lt;BR&gt;&lt;BR&gt;// inside the Loaded function, we add code behind our MouseWheelHelper code added earlier.. &lt;BR&gt;DeepZoom.MouseLeftButtonDown += &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;MouseButtonEventHandler&lt;/SPAN&gt;(DeepZoom_MouseLeftButtonDown); &lt;BR&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;The handler looks like this: &lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;protected bool &lt;/SPAN&gt;_isDragging = &lt;SPAN style="COLOR: blue"&gt;false&lt;/SPAN&gt;;
&lt;SPAN style="COLOR: blue"&gt;protected &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Point &lt;/SPAN&gt;_lastDragViewportOrigin; 
&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;DeepZoom_MouseLeftButtonDown(&lt;SPAN style="COLOR: blue"&gt;object &lt;/SPAN&gt;sender, &lt;SPAN style="COLOR: #2b91af"&gt;MouseButtonEventArgs &lt;/SPAN&gt;e)
{
            &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;._lastDragViewportOrigin = DeepZoom.ViewportOrigin;
            &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;._lastMousePosition = e.GetPosition(DeepZoom);
            &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;._isDragging = &lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;; 
           
}&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;Now we subscribe to MouseLeftButtonUp, inside Loaded function&amp;nbsp; and we add the handler function for it. &lt;BR&gt;&lt;BR&gt;//&amp;nbsp; The one liner below goes in the Page_Loaded event handler &lt;BR&gt;DeepZoom.MouseLeftButtonUp += &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;MouseButtonEventHandler&lt;/SPAN&gt;(DeepZoom_MouseLeftButtonUp); &lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;DeepZoom_MouseLeftButtonUp(&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;sender, &lt;SPAN style="COLOR: #2b91af"&gt;MouseButtonEventArgs &lt;/SPAN&gt;e) &lt;BR&gt;{ &lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this&lt;/SPAN&gt;._isDragging = &lt;SPAN style="COLOR: blue"&gt;false&lt;/SPAN&gt;; &lt;BR&gt;} &lt;BR&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;Now we tweak the code inside MouseMove&amp;nbsp; to Change the ViewportOrigin to perform the Pan operation. &lt;BR&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;DeepZoom_MouseMove(&lt;SPAN style="COLOR: blue"&gt;object &lt;/SPAN&gt;sender, &lt;SPAN style="COLOR: #2b91af"&gt;MouseEventArgs &lt;/SPAN&gt;e)
{
&lt;SPAN style="COLOR: blue"&gt;  if &lt;/SPAN&gt;(_isDragging)
  {
&lt;SPAN style="COLOR: #2b91af"&gt;&lt;FONT color=#333333&gt;   &lt;/FONT&gt;Point &lt;/SPAN&gt;newViewport = _lastDragViewportOrigin;
   &lt;SPAN style="COLOR: #2b91af"&gt;Point &lt;/SPAN&gt;currentMousePosition = e.GetPosition(DeepZoom);
   newViewport.X += (_lastMousePosition.X - currentMousePosition.X) &lt;BR&gt;/ &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ActualWidth * &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportWidth;
   newViewport.Y += (_lastMousePosition.Y - currentMousePosition.Y) &lt;BR&gt;/ &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ActualWidth * &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportWidth;
   &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin = newViewport;
   _lastDragViewportOrigin = newViewport; 
  }
  // NOTE: it is important this be after the isDragging check … &lt;BR&gt;  // since this updates last position, which is used to compare for dragging. 
 _lastMousePosition = e.GetPosition(DeepZoom);
}&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;We should also detect the MouseLeave event, and if we are in the middle of a Pan, we need to reset the _isDragging flag. &lt;BR&gt;&lt;BR&gt;// inside the UserControl Loaded handler DeepZoom.MouseLeave += &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;MouseEventHandler&lt;/SPAN&gt;(DeepZoom_MouseLeave);&lt;SPAN style="COLOR: blue"&gt; &lt;BR&gt;void &lt;/SPAN&gt;DeepZoom_MouseLeave(&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;sender, &lt;SPAN style="COLOR: #2b91af"&gt;MouseEventArgs &lt;/SPAN&gt;e) &lt;BR&gt;{ &lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;._isDragging = &lt;SPAN style="COLOR: blue"&gt;false&lt;/SPAN&gt;; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.Cursor = &lt;SPAN style="COLOR: #2b91af"&gt;Cursors&lt;/SPAN&gt;.Arrow;&amp;nbsp; &lt;BR&gt;}&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;BR&gt;&lt;BR&gt;&lt;/LI&gt;&lt;/OL&gt;&lt;/LI&gt;
&lt;LI&gt;&amp;nbsp; That is it for the basics and the ‘hard stuff’ … with not too many lines of code, we have Zoom &amp;amp; Pan in our host.&amp;nbsp; Along the way we added a few properties we can reuse to create UI around our DeepZoom image. &lt;BR&gt;&lt;BR&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;H1&gt;Part 4.1 Adding more UI to navigate in a DeepZoom Control. &lt;BR&gt;&lt;/H1&gt;
&lt;P&gt;In the last sections I took it slow and walked through the code to explain what we were working on.&amp;nbsp; Going forward below will pick up the pace a bit, and the original code will be tweaked to get into a host control with a bit more navigation and troubleshooting advise.&amp;nbsp; &lt;BR&gt;&lt;/P&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=2 width="100%" border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top&gt;We begin by adding a Navigation wheel to the UserControl.xaml.&amp;nbsp; The wheel has four repeat buttons with arrows pointing east,west,north, south; these buttons will be used to pan in the respective direction. &lt;BR&gt;&lt;BR&gt;At the center of the wheel, there is a regular button, which takes you home ( to where there is no Zoom, no panning, etc. ) &lt;/TD&gt;
&lt;TD class="" vAlign=top width=200&gt;&lt;BR&gt;&lt;A href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_10.png" mce_href="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_10.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=98 alt=image src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_thumb_4.png" width=100 border=0 mce_src="http://blogs.msdn.com/blogfiles/jaimer/WindowsLiveWriter/Deepzoomprimerpart12_A83/image_thumb_4.png"&gt;&lt;/A&gt; &lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;OL&gt;
&lt;LI&gt;Implementing Panning is done by changing the viewportOrigin. We have a choice of Panning relative to control size and relative to ImageSize. Let me explain: &lt;BR&gt;&lt;BR&gt;If the controls ViewPortWidth is 1.0 – and we pan by a Logical increment of 0.1&amp;nbsp; we are panning 10 percent on a direction. This % seems reasonable. &lt;BR&gt;If however we are zoomed in 500% ( viewportWidth = 0.2 ) and we do a Pan of 0.1 (logical)&amp;nbsp; then we are going to pan by a lot ( 50% of what is visible).&amp;nbsp; So we need to scale our original 0.1 increment by the ViewportWidth.&amp;nbsp; Don’t you think? &lt;BR&gt;&lt;BR&gt;Here is what I did: 
&lt;OL&gt;
&lt;LI&gt;Added a Property of type double called&amp;nbsp; PanPercent.&amp;nbsp;&amp;nbsp; This property holds the increment. You can set it from XAML; default is 0.1&amp;nbsp; ( aka 10% ) &lt;/LI&gt;
&lt;LI&gt;Added a property of type bool called UseViewportScaleOnPan.&amp;nbsp; If this is true, we will pan by&amp;nbsp; PanPercent * ViewportWidth; if this is false we pan by PanPercent. &lt;BR&gt;&lt;/LI&gt;&lt;/OL&gt;&lt;/LI&gt;
&lt;LI&gt;Now we are ready for Panning. We add event handlers for all our Pan RepeatButtons: &lt;BR&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.PanRight.Click += &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;RoutedEventHandler&lt;/SPAN&gt;(PanRight_Click);
&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.PanLeft.Click += &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;RoutedEventHandler&lt;/SPAN&gt;(PanLeft_Click);
&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.Home.Click += &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;RoutedEventHandler&lt;/SPAN&gt;(Home_Click);
&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.PanBottom.Click += &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;RoutedEventHandler&lt;/SPAN&gt;(PanBottom_Click);
&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.PanTop.Click += &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;RoutedEventHandler&lt;/SPAN&gt;(PanTop_Click);&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;Each of the event handlers calls the Pan function with their respective direction: &lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;Pan(&lt;SPAN style="COLOR: #2b91af"&gt;PanDirection &lt;/SPAN&gt;direction)
{
&lt;SPAN style="COLOR: blue"&gt;double &lt;/SPAN&gt;percent = PanPercent; 
            
&lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;( UseViewportScaleOnPan ) 
    percent *= &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportWidth; 
&lt;SPAN style="COLOR: blue"&gt;switch &lt;/SPAN&gt;(direction)
{               
&lt;SPAN style="COLOR: blue"&gt;&lt;FONT color=#333333&gt;   &lt;/FONT&gt;case &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;PanDirection&lt;/SPAN&gt;.East:
&lt;SPAN style="COLOR: blue"&gt;&lt;FONT color=#333333&gt;      &lt;/FONT&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin =
         &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Point&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin.X - &lt;SPAN style="COLOR: #2b91af"&gt;Math&lt;/SPAN&gt;.Min(percent, &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin.X),
      &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin.Y);
         &lt;SPAN style="COLOR: blue"&gt;break&lt;/SPAN&gt;; 
&lt;SPAN style="COLOR: blue"&gt;&lt;FONT color=#333333&gt;   &lt;/FONT&gt;case &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;PanDirection&lt;/SPAN&gt;.West:
       &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin =
           &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Point&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin.X + &lt;SPAN style="COLOR: #2b91af"&gt;Math&lt;/SPAN&gt;.Min(percent, (1.0 - &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin.X)),
            &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin.Y);
                    &lt;SPAN style="COLOR: blue"&gt;break&lt;/SPAN&gt;; 
&lt;SPAN style="COLOR: blue"&gt;&lt;FONT color=#333333&gt;    &lt;/FONT&gt;case &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;PanDirection&lt;/SPAN&gt;.South :
         &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin =
          &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Point&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin.X ,
           &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin.Y + &lt;SPAN style="COLOR: #2b91af"&gt;Math&lt;/SPAN&gt;.Min( percent, 1.0 - &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin.Y));
        &lt;SPAN style="COLOR: blue"&gt;break&lt;/SPAN&gt;; 
     &lt;SPAN style="COLOR: blue"&gt;case &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;PanDirection&lt;/SPAN&gt;.North :
          &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin =
             &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Point&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin.X,
             &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin.Y - &lt;SPAN style="COLOR: #2b91af"&gt;Math&lt;/SPAN&gt;.Min( percent, &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin.Y));
          &lt;SPAN style="COLOR: blue"&gt;break&lt;/SPAN&gt;; 
     } &lt;BR&gt;}&lt;BR&gt;&lt;BR&gt;&lt;/PRE&gt;&lt;/LI&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;LI&gt;Panning to Home is a combination of setting the ViewportOrigin to 0,0 and setting the ViewportWidth to 1 &lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;Home_Click(&lt;SPAN style="COLOR: blue"&gt;object &lt;/SPAN&gt;sender, &lt;SPAN style="COLOR: #2b91af"&gt;RoutedEventArgs &lt;/SPAN&gt;e) { &lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportOrigin = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Point&lt;/SPAN&gt;(0, 0); &lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.DeepZoom.ViewportWidth = 1; } &lt;BR&gt;&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Next thing is to implement Zoom in and Zoom Out; these are also trivial, the only decision to make is where to Zoom, I needed two approaches: &lt;BR&gt;When Zooming using keyboard,&amp;nbsp; Ctrl+ Ctrl- (on Windows)&amp;nbsp; I wanted to Zoom at the mousePosition.&amp;nbsp; &lt;BR&gt;When zooming using the magnifying glass icons I added to the UI, I can not use the mousePosition – as I knew the mouse was where the magnifying glass – so I zoomed around the center of the control. &lt;BR&gt;&lt;BR&gt;Let’s begin with simple ZoomIn using Click from magnifying glass: &lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;&lt;BR&gt;void &lt;/SPAN&gt;btnZoomIn_Click(&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;sender, &lt;SPAN style="COLOR: #2b91af"&gt;RoutedEventArgs &lt;/SPAN&gt;e) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ZoomIn( &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Point&lt;/SPAN&gt;( DeepZoom.ActualWidth / 2 , DeepZoom.ActualHeight / 2));&amp;nbsp; &lt;BR&gt;} &lt;BR&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;Zooms in around an ELEMENT Coordinate..  
&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;/// &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;I technically did not need this function to abstract and could have called DoZoom directly 
&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name="p"&amp;gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;ZoomIn( &lt;SPAN style="COLOR: #2b91af"&gt;Point &lt;/SPAN&gt;p )
{
    &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(_useRelatives)
        DoRelativeZoom(Zoom / DefaultZoomFactor, p, &lt;SPAN style="COLOR: #2b91af"&gt;ZoomDirection&lt;/SPAN&gt;.In);
    &lt;SPAN style="COLOR: blue"&gt;else
        &lt;/SPAN&gt;DoZoom(DefaultZoomFactor, p );
} &lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;When zooming from Keyboard.&amp;nbsp; The “gotcha” was that the DeepZoomImage is a FrameworkElement and it does not receive focus (in Silverlight Focus is at Control class), so what I did was listen for Keyboard event in the Grid that is the top container in my Host UserControl.&amp;nbsp; &lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.LayoutRoot.KeyUp += &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;KeyEventHandler&lt;/SPAN&gt;(DeepZoom_KeyUp);&lt;BR&gt;&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;Another surprise was that + (by pressing Shift+9) on my machine turned out to be a keycode, not a standard key.&amp;nbsp; I am not a keyboard expert in Silverlight (yet) but from what I read, keycodes can be different across platform so I added code to check in case I am running in the Mac. I checked using the Environment.OSVersion property.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Please double check this code, as I was pretty lazy about what running on Windows or Mac means.&amp;nbsp; &lt;/LI&gt;
&lt;LI&gt;&lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;public bool &lt;/SPAN&gt;RunningOnWindows &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;get &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt;( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: #2b91af"&gt;Environment&lt;/SPAN&gt;.OSVersion.Platform == &lt;SPAN style="COLOR: #2b91af"&gt;PlatformID&lt;/SPAN&gt;.Win32NT || &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: #2b91af"&gt;Environment&lt;/SPAN&gt;.OSVersion.Platform == &lt;SPAN style="COLOR: #2b91af"&gt;PlatformID&lt;/SPAN&gt;.Win32S);&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;Now we do the Zoom, note that I am not too confident on my Mac KeyCodes; I got this by sniffing on my Mini but I have a regular,ergonomic Microsoft keyboard on&amp;nbsp; that mini so double check with your keyboard just in case. &lt;SPAN style="COLOR: blue"&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;DeepZoom_KeyUp(&lt;SPAN style="COLOR: blue"&gt;object &lt;/SPAN&gt;sender, &lt;SPAN style="COLOR: #2b91af"&gt;KeyEventArgs &lt;/SPAN&gt;e)
{
            
&lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(e.Handled == &lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;)
&lt;SPAN style="COLOR: blue"&gt;&lt;FONT color=#333333&gt;   &lt;/FONT&gt;return&lt;/SPAN&gt;;

&lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;( ( RunningOnWindows &amp;amp;&amp;amp; ((&lt;SPAN style="COLOR: #2b91af"&gt;Keyboard&lt;/SPAN&gt;.Modifiers &amp;amp; &lt;SPAN style="COLOR: #2b91af"&gt;ModifierKeys&lt;/SPAN&gt;.Control) == &lt;SPAN style="COLOR: #2b91af"&gt;ModifierKeys&lt;/SPAN&gt;.Control) &amp;amp;&amp;amp;
     (e.Key == &lt;SPAN style="COLOR: #2b91af"&gt;Key&lt;/SPAN&gt;.Add || (e.Key == &lt;SPAN style="COLOR: #2b91af"&gt;Key&lt;/SPAN&gt;.Unknown &amp;amp;&amp;amp; e.PlatformKeyCode == 0xBB)))  ||
     ( RunningOnMac &amp;amp;&amp;amp; ((&lt;SPAN style="COLOR: #2b91af"&gt;Keyboard&lt;/SPAN&gt;.Modifiers &amp;amp; &lt;SPAN style="COLOR: #2b91af"&gt;ModifierKeys&lt;/SPAN&gt;.Control) == &lt;SPAN style="COLOR: #2b91af"&gt;ModifierKeys&lt;/SPAN&gt;.Control) &amp;amp;&amp;amp;
     (e.Key == &lt;SPAN style="COLOR: #2b91af"&gt;Key&lt;/SPAN&gt;.Add || (e.Key == &lt;SPAN style="COLOR: #2b91af"&gt;Key&lt;/SPAN&gt;.Unknown &amp;amp;&amp;amp; e.PlatformKeyCode == 0x18 )))
                 
    )
    {
       ZoomIn( _lastMousePosition); 

    }
    &lt;SPAN style="COLOR: blue"&gt;else if &lt;/SPAN&gt;( 
      (RunningOnWindows &amp;amp;&amp;amp; ((&lt;SPAN style="COLOR: #2b91af"&gt;Keyboard&lt;/SPAN&gt;.Modifiers &amp;amp; &lt;SPAN style="COLOR: #2b91af"&gt;ModifierKeys&lt;/SPAN&gt;.Control) == &lt;SPAN style="COLOR: #2b91af"&gt;ModifierKeys&lt;/SPAN&gt;.Control) &amp;amp;&amp;amp;
      (e.Key == &lt;SPAN style="COLOR: #2b91af"&gt;Key&lt;/SPAN&gt;.Add || (e.Key == &lt;SPAN style="COLOR: #2b91af"&gt;Key&lt;/SPAN&gt;.Unknown &amp;amp;&amp;amp; e.PlatformKeyCode == 0xBD)))||
      ( RunningOnMac &amp;amp;&amp;amp; ((&lt;SPAN style="COLOR: #2b91af"&gt;Keyboard&lt;/SPAN&gt;.Modifiers &amp;amp; &lt;SPAN style="COLOR: #2b91af"&gt;ModifierKeys&lt;/SPAN&gt;.Control) == &lt;SPAN style="COLOR: #2b91af"&gt;ModifierKeys&lt;/SPAN&gt;.Control) &amp;amp;&amp;amp;
      (e.Key == &lt;SPAN style="COLOR: #2b91af"&gt;Key&lt;/SPAN&gt;.Add || (e.Key == &lt;SPAN style="COLOR: #2b91af"&gt;Key&lt;/SPAN&gt;.Unknown &amp;amp;&amp;amp; e.PlatformKeyCode == 0x1B )))
     )
   {
      ZoomOut( _lastMousePosition );
   }            
             
   e.Handled = &lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;;
 }&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;At&amp;nbsp; that point our app would be functionally complete but I want to share a few more findings from my learning so let me share&amp;nbsp; the DebugSpew, it can be handy for you too. &lt;BR&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;OL&gt;
&lt;LI&gt;When I wrote my first deepZoom app, I took the usual approach of databinding to it so I can reverse engineer it and found a few issues; since I am traveling I have not discussed them w/ DeepZoom folks in depth for now take these as “gotchas in beta1” and will try to get some one from DeepZoom team to confirm if these are ‘final’ behaviors (feel free to leave feedback here or at the expression blog) letting them know your preferences. 
&lt;UL&gt;
&lt;LI&gt;Databinding to MultiScaleImage was a bit flaky.&amp;nbsp;&amp;nbsp; ViewportWidth and ViewportOrigin did not fire notifications for me.&amp;nbsp; The explanation I have seen is that&amp;nbsp; because DeepZoom animates with springs, binding to these properties was not recommended.&amp;nbsp; These values will change every frame during a transition.&amp;nbsp;&amp;nbsp; The recommended workaround was to subscribe to the MotionFinished event.&amp;nbsp; This fires at the end of a transition, so gives me a nice way to pull the value.&amp;nbsp; In my case (for debug/learning deepZoom), the workaround&amp;nbsp; was very acceptable so I implemented it. &lt;BR&gt;&lt;BR&gt;// in my loaded event for the page &lt;BR&gt;DeepZoom.MotionFinished += &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;RoutedEventHandler&lt;/SPAN&gt;(DeepZoom_MotionFinished); &lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;DeepZoom_MotionFinished(&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;sender, &lt;SPAN style="COLOR: #2b91af"&gt;RoutedEventArgs &lt;/SPAN&gt;e) &lt;BR&gt;{ &lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;nbsp;&amp;nbsp; if&lt;/SPAN&gt;(DebugSpew.DataContext != &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;) &lt;BR&gt;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: #2b91af"&gt;MultiScaleImageDummyDataWrapper &lt;/SPAN&gt;dw = DebugSpew.DataContext &lt;SPAN style="COLOR: blue"&gt;as&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;MultiScaleImageDummyDataWrapper&lt;/SPAN&gt;; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;if&lt;/SPAN&gt;(dw != &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PullData(&lt;SPAN style="COLOR: blue"&gt;ref&lt;/SPAN&gt;dw, &lt;SPAN style="COLOR: blue"&gt;ref&lt;/SPAN&gt;DeepZoom); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MouseLogicalPosition = DeepZoom.ElementToLogicalPoint(_lastMousePosition); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp; &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp; &lt;BR&gt;&lt;BR&gt;&amp;nbsp; } &lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;PullData(&lt;SPAN style="COLOR: blue"&gt;ref &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;MultiScaleImageDummyDataWrapper &lt;/SPAN&gt;data, &lt;SPAN style="COLOR: blue"&gt;ref &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;MultiScaleImage &lt;/SPAN&gt;msi)
{
            data.ViewportWidth = msi.ViewportWidth;
            data.ViewportOrigin = msi.ViewportOrigin;
            data.AspectRatio = msi.AspectRatio;
            data.UseSprings = msi.UseSprings; 
             
} &lt;/PRE&gt;&lt;/LI&gt;
&lt;LI&gt;Databinding to the other properties (that are not animated per frame) in MultiScaleImage also gave me a bit of trouble [some times the control would not show up]. My advise is to not data bind for now.&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Once I had the databinding worked out, I added a handler to pull data from the MouseMove so I could show coordinates when Mouse is moving, I wanted them in logical and element coordinates, so I did the translation and I added an extra&amp;nbsp; call from MotionFinished to translate the point again as the logical Coordinate changes when the Viewport changes. &lt;BR&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/OL&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;H1&gt;Part 5 – Lessons learned &lt;/H1&gt;
&lt;P&gt;Overall I was quite impressed with DeepZoom. it is pretty cool stuff; I wish I had some cool pictures for a better application, but I did not try since&amp;nbsp; I knew I could not top memorabilia. &lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;
&lt;P&gt;My personal advise:&amp;nbsp; do not databind to DeepZoom for now. Pull to it on Motion Finished. &lt;/P&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;No keyboard input goes into DeepZoom (since it is a FrameworkElement). In order to have keyboard input you must have a Control that has focus; since keyboard events bubble you can handle Keyboard input at a higher level (e.gl LayoutRoot, just check to see if it has not been handled previously). &lt;/P&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;On my real app –which can’t be shared as it was a customer’s app –.&amp;nbsp; I ran into an issue when using Collections. My images were showing up in the wrong place.&amp;nbsp; I reported it already and they are investigating –during the shower, where I do my best thinking- I came with the theory that is the resolution independence in WPF ( 96 to 72 DPI conversion).&amp;nbsp; I have not confirmed. &lt;/P&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;I did not discuss collections in the post, so will try it here. Collections are cool because it gives you access to your Subimages so you can&amp;nbsp; manipulate them.&amp;nbsp; Move them around, scale them, animate position and Opacity.&amp;nbsp;&amp;nbsp; For now, beta1 has only one Collection; I think it would be cool to have multiple collections so you can aggregate.&amp;nbsp; This can kind of be simulated via logic, but would be nice if it was in the control.&amp;nbsp; If you simulate it, the advise I was given is do not simulate it by overlaying two MultiScaleImage controls one on top of the other, there are a few known issues with interactions on overlays (though to be honest I tried it and did not run into issues). &lt;/P&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;UseSprings= true is pretty cool, but pending how quick you want to do your panning/zooming, turning it off can make your app appear more responsive. I would not turn UseSprings off for a consumer facing app, but I would consider doing it for an internal app.. For example, I am doing a Heatmap with lots of data in it, for analytical purposes. Since it is drill through I am considering it. &lt;/P&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;When panning, make sure you handle MouseLeave on your control. &lt;/P&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;Handling mouse wheel is not available out of the box is trivial but Peter Blois has a great solution. Do not&amp;nbsp; write the code to handle wheel. Peter’s code works great so far. Check his blog for updates too, he has a nice abstraction now to the same API. &lt;/P&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;If you skipped section 3, check it out. Understanding the object model is critical and takes 5 mins. &lt;/P&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;If you are writing a DeepZoom application, I recommend you use the old instantiation via silverlight.js … Click To Activate will eventually go away in IE, but in the mean time it is pretty annoying for an app that is so visual and so focused on mouse navigation.&amp;nbsp; &lt;/P&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;If subscribing to MultiScaleImage.OpenImageSucceded make sure you do it from your constructor right after initializeComponent.&amp;nbsp; I tried to do it of&amp;nbsp; UserControl.Loaded and when doing a load on a page with image cached that is too late. &lt;/P&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;If possible try to ‘hold’ any operations until OpenImageSucceded has fired ( no pans, zooms before that). I saw weird results if I try to access properties on MultiScaleImage before this event; in particular if you access the SubImages collection before ImageOpenSucceded, then I would get an empty collection and when ImageOpenSucceeded was fired, the collection would not be overridden; so advise for collections is don’t touch SubImages before the OpenImageSucceeded fires. &lt;/P&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;H1&gt;Part 6 – Source &lt;/H1&gt;
&lt;P&gt;Is at &lt;A title=http://cid-123ec1ed6c72a14a.skydrive.live.com/self.aspx/Public/DeepZoomSample.zip href="http://cid-123ec1ed6c72a14a.skydrive.live.com/self.aspx/Public/DeepZoomSample.zip" mce_href="http://cid-123ec1ed6c72a14a.skydrive.live.com/self.aspx/Public/DeepZoomSample.zip"&gt;Skydrive&lt;/A&gt;&lt;/P&gt;
&lt;H1&gt;Part 7 – Show me the app. &lt;/H1&gt;
&lt;P&gt;You can see it &lt;A href="http://www.cookingwithxaml.com/meals/deepzoomsample/default.html" mce_href="http://www.cookingwithxaml.com/meals/deepzoomsample/default.html"&gt;here&lt;/A&gt;;&amp;nbsp; it is not visually impressive but I think it shows a bit of what you can do with DeepZoom and most important it is functional code you can quickly refactor and reuse. If I missed a common deepZoom task let me know. &lt;BR&gt;&amp;nbsp; &lt;BR&gt;I added two extra “easter eggs” beyond the bunny and&amp;nbsp; the eggs above in the walk through. &lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;One is for&amp;nbsp; the NCAA basketball team for my college, which won yesterday and made it to the Final Four tournament .&amp;nbsp; (Hint, the four finalists are:&amp;nbsp; Kansas, Memphis, UCLA and North Carolina. &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;The other one is a bitmap with dates &amp;amp; locations for my upcoming Europe trip (Germany, Austria)..&amp;nbsp; If you are in the area and available the nights I am in the area, ping me and we can get together to discuss any thing .NET client related (e.g. WPF, Silverlight, and ASPX). &lt;/LI&gt;&lt;/OL&gt;
&lt;H1&gt;Part 8 -- Thanks&lt;/H1&gt;
&lt;P&gt;Thanks to &lt;A href="http://systim.spaces.live.com/" mce_href="http://systim.spaces.live.com/"&gt;Tim Aidlin&lt;/A&gt; who chose the colors and gave me cooler icons for the map; I butchered them a bit when I turned them into controls so don’t hold it against him, he is a gifted designer –you can see his real work on the MIX website and any thing else MIX08 branded. &lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8347451" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jaimer/archive/tags/expression/default.aspx">expression</category><category domain="http://blogs.msdn.com/jaimer/archive/tags/silverlight/default.aspx">silverlight</category><category domain="http://blogs.msdn.com/jaimer/archive/tags/deepzoom/default.aspx">deepzoom</category></item></channel></rss>