<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Kael Rowan</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/kaelr/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/kaelr/feed.xml</link>
    <description>Foundations of Elegant Code</description>
    <lastBuildDate>Tue, 16 Apr 2019 05:15:02 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Debugger Canvas on Channel9</title>
      <link>https://docs.microsoft.com/archive/blogs/kaelr/debugger-canvas-on-channel9</link>
      <pubDate>Wed, 23 May 2012 10:01:03 GMT</pubDate>
      <dc:creator><![CDATA[Kael Rowan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaelr/2012/05/23/debugger-canvas-on-channel9/</guid>
      <description><![CDATA[Hi everyone, Robert Green from Channel9 asked me to do a Debugger Canvas video for Channel9 last...]]></description>
      <content:encoded><![CDATA[<p>Hi everyone, Robert Green from Channel9 asked me to do a <a href="http://msdn.microsoft.com/en-us/devlabs/hh227299">Debugger Canvas</a> video for <a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Visual-Studio-Toolbox-Debugger-Canvas">Channel9</a> last week and it went live today.&#160; Check it out! </p>  <p><a href="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Visual-Studio-Toolbox-Debugger-Canvas">https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Visual-Studio-Toolbox-Debugger-Canvas</a>    <br /><iframe style="width: 512px; height: 288px" src="https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Visual-Studio-Toolbox-Debugger-Canvas/player?w=512&amp;h=288" frameborder="0" scrolling="no"></iframe></p>]]></content:encoded>
    </item>
    <item>
      <title>Exploring Code Canvas</title>
      <link>https://docs.microsoft.com/archive/blogs/kaelr/exploring-code-canvas</link>
      <pubDate>Sat, 14 Apr 2012 16:07:00 GMT</pubDate>
      <dc:creator><![CDATA[Kael Rowan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaelr/2012/04/14/exploring-code-canvas/</guid>
      <description><![CDATA[Introduction
I originally started working on Code Canvas back in 2007, but it was essentially put...]]></description>
      <content:encoded><![CDATA[<h1 style="clear: both">Introduction</h1>
I originally started working on <a href="http://research.microsoft.com/en-us/projects/codecanvas/">Code Canvas</a> back in 2007, but it was essentially put on hold after 2009 because the technology to make it testable in the field was not available.  For example, Visual Studio at the time did not support editing code in anything other than the standard file-based tabbed-editors.  Also there was too much work required to integrate Code Canvas into the rest of the IDE, but this integration would have been necessary in order to test it with real developers on real code.  Right about this time <a href="http://brown.edu/">Brown University</a> came out with their own canvas-based environment called <a href="http://www.andrewbragdon.com/codebubbles_site.asp">Code Bubbles</a> which we wanted to collaborate on, so we created a project called <a href="http://msdn.microsoft.com/en-us/devlabs/hh227299">Debugger Canvas</a> which combined aspects of Code Canvas and Code Bubbles together.  Debugger Canvas was a success and is alive and well on Microsoft <a href="http://msdn.microsoft.com/devlabs/">DevLabs</a> with over 15,000 downloads so far.

Debugger Canvas is similar to Code Canvas but is really only a small piece of the overall vision of Code Canvas. Code Canvas aims to let the developer view and interact with their entire software system as a whole, much like a code map or schematic, whereas Debugger Canvas only lasts for one debugging session and is only meant to make that debugging session easier to understand.  You can read more on my personal thoughts and comparisons of Code Canvas vs. Code Bubbles vs. Debugger Canvas in <a href="http://blogs.msdn.com/b/kaelr/archive/2012/03/10/code-canvas-vs-code-bubbles-vs-debugger-canvas.aspx">my previous blog post</a>.

Now that more than three years have passed since the <a href="http://blogs.msdn.com/b/kaelr/archive/2009/03/26/code-canvas.aspx">original Code Canvas prototypes</a> were created, the world has begun moving away from monolithic desktop applications built on black-box frameworks and is building more highly distributed web/browser-based applications using HTML5, JavaScript, CSS3, etc.  Current developer tools for the web are even more in need of the types of benefits that Code Canvas aims to provide, and this new target audience is a prime candidate for continuing the research where we left off and exploring the new research aspects that we haven’t touched yet.  Here is a list of the features we’ve explored and a sampling of the kinds of topics we’d like to research in the future.

<h1 style="clear: both">Prototyped Features</h1>
The first major Code Canvas prototype was a standalone Windows application based on WPF and was shown at <a href="http://blogs.msdn.com/b/kaelr/archive/2009/11/09/code-canvas-techfest.aspx">MSR TechFest in 2009</a>. The demo consisted of several features that worked together to give the concept of what code on a canvas might look like and the possibilities that you could do with it.

<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/0488.Code-Canvas-TechFest-Poster_27A1205A.png"><img style="padding-left: 0px;padding-right: 0px;padding-top: 0px;border-width: 0px" title="Code Canvas TechFest Poster" border="0" alt="Code Canvas TechFest Poster" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/6864.Code-Canvas-TechFest-Poster_thumb_7D053F7C.png" width="1028" height="772" /></a>

<h2 style="clear: both">All Code Simultaneously on a Single Zoomable Surface</h2>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/6507.WPFRibbon-in-Code-Canvas-Files_3B98FEC7.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="WPFRibbon in Code Canvas (Files)" border="0" alt="WPFRibbon in Code Canvas (Files)" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/6505.WPFRibbon-in-Code-Canvas-Files_thumb_2848225B.png" width="219" height="240" /></a>At the heart of Code Canvas is the ability to view all of a system’s source code, designers, and artifacts at the same time next to each other on a single zoomable canvas. The prototype demoed at TechFest did not have the ability to show visual designers yet, but it did show what it would be like to have multiple C# code files on a canvas next to each other at the same time.  The figure on the right shows the entire source code for the old CTP of the <a href="http://wpf.codeplex.com/wikipage?title=WPF%20Ribbon%20Preview">WPF Ribbon Preview</a> from <a href="http://www.codeplex.com">www.codeplex.com</a>.

By itself this is not so impressive (even though it was incredibly difficult to get it to scale well), but this was the foundation for all of the features that came next.

<h2 style="clear: both">View Code based on More than just Files and Directories</h2>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/0247.WPFRibbon-in-Code-Canvas-Classes_3B88D8FA.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="WPFRibbon in Code Canvas (Classes)" border="0" alt="WPFRibbon in Code Canvas (Classes)" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/7103.WPFRibbon-in-Code-Canvas-Classes_thumb_28A42F83.png" width="219" height="240" /></a>Since most codebases today are organized based on files and directories, Code Canvas of course has the ability to display them as such.  But one of the earliest design goals of Code Canvas was to have the ability to view your code based on the structure of the code instead of its organization on disk.  The first prototype had the ability to make the code on the canvas look like Visual Studio’s Class Diagram instead, by drawing borders and backgrounds behind type definitions using the same colors and shapes as the built-in Class Diagram view.  You’ll need to look at the figures in high detail to see the difference when zoomed out, but viewing the code based on its types instead of its files makes it easy to see how many types there are, the relative size of them, and even makes nested types much more obvious than they would have if viewing the code in traditional text editors.

<div style="clear: both"></div>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/0143.Files-Types-and-Folders_22D11CDF.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="Files, Types, and Folders" border="0" alt="Files, Types, and Folders" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/6888.Files-Types-and-Folders_thumb_7D672970.png" width="172" height="240" /></a>You can also turn on all of these views at once.  In that case, you will see the files surrounded by the silver file background with the class diagram graphics layered on top and the directory/group background colors underneath.  In the case of C# files that consist mainly of one gigantic type definition, the only place you’d really notice the silver file background would be behind the <span style="font-family: consolas, courier"><span style="color: blue">using</span></span> statements and the <span style="font-family: consolas, courier"><span style="color: blue">namespace</span></span> declaration.

<h2 style="clear: both">Fluid Semantic Zoom</h2>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/3157.WPFRibbon-in-Code-Canvas-Members_7C470FA9.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="WPFRibbon in Code Canvas (Members)" border="0" alt="WPFRibbon in Code Canvas (Members)" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/6786.WPFRibbon-in-Code-Canvas-Members_thumb_3E1DCF2B.png" width="219" height="240" /></a><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/8666.WPFRibbon-in-Code-Canvas-Zoomed-In_43F872C4.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="WPFRibbon in Code Canvas (Zoomed In)" border="0" alt="WPFRibbon in Code Canvas (Zoomed In)" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/4643.WPFRibbon-in-Code-Canvas-Zoomed-In_thumb_20E80154.png" width="192" height="240" /></a>Code Canvas takes the approach of zooming out instead of scrolling when you run out of space on your screen (although you could certainly pan everywhere instead of zooming if you liked).  Unfortunately as you’re zooming out then everything quickly becomes too small to read.  But that’s ok, since when you’re zooming out it’s reasonable to assume you want a “higher level” view of your system anyway, for example the view offered by Visual Studio’s Class Diagram which only shows you boxes and names of types and members without showing you any of the actual code.  We could have abruptly switched from one view to the other at some predefined level of zoom, but that would be jarring to the user and may even make it feel like two disconnected views.

<div style="clear: both"></div>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/3348.Squishing-Labels_3C58AA0C.gif"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="Squishing Labels" border="0" alt="Squishing Labels" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/7043.Squishing-Labels_thumb_4AD3A631.gif" width="172" height="240" /></a>Instead, Code Canvas slowly introduces floating labels with icons as soon as the zoom level is less than 99%, and the labels line up exactly with the text identifiers defining the types and members.  As the user zooms out, the floating labels and icons stay the same size even though everything else becomes smaller and smaller.  The floating icons and labels are anchored to the defining text in the code (which gets closer together as the user zooms out) but since the icons and labels don’t get <em>smaller</em> then they eventually start to collide.   When this happens, they push each other out of the way but maintain their relative order so that they begin to stack vertically like a list.  The labels are constrained to the boundaries of their containing type, so eventually they also run out of room horizontally and vertically, at which point their either clip or “squish” together, with the private members squishing out of existence first, then the protected members, then the public members, etc..

Since the floating labels are opaque, they eventually cover up all of the teeny tiny code behind them and all the user is left with is a bunch of the icons and labels stacked on top of each other which looks pretty much like the view in the Class Diagram does.  This all happens fluidly and dynamically in real-time as the zoom scale increases and decreases so that it truly feels like the same content as the user zooms in and out.

<h2 style="clear: both">Automatic Layout and Edge Routing</h2>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/2526.A-Z-Graph-Layout_0A23EF31.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="A-Z Graph Layout" border="0" alt="A-Z Graph Layout" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/7220.A-Z-Graph-Layout_thumb_40456780.png" width="130" height="240" /></a><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/6712.WPFRibbon-in-Code-Canvas-Layout_64AA979C.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="WPFRibbon in Code Canvas (Layout)" border="0" alt="WPFRibbon in Code Canvas (Layout)" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/0447.WPFRibbon-in-Code-Canvas-Layout_thumb_7D2A0F1F.png" width="240" height="142" /></a>While it’s possible to drag everything around by hand on the canvas just like you would in a diagramming program, there are times when you would rather automatically arrange the code based on some rule or structure (such as class inheritance for example).  Code Canvas used <a href="http://research.microsoft.com/en-us/projects/msagl/">Microsoft’s Automatic Graph Layout</a> libraries to accomplish this.  Unfortunately the built-in algorithms were tailored towards large node-link diagrams where nodes would align their midpoints (instead of aligning their top or bottom edges with each other).  When moving nodes around they would also attempt to “gravitate” towards one another to continually optimize for the shortest paths and minimal edge crossings.  Code Canvas also has similar desires (short edge lengths, minimal edge crossings), but after playing with the layout it felt very odd to have the code fragments “floating” around.  A much more grid-based (or line/column-based) layout algorithm is needed in order to line up lines of code and left-side margins since we are usually dealing with fixed-width text and not the typical nodes or “bubbles” that are common in graph-based layout algorithms today.

<h2 style="clear: both">Groups</h2>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/8156.All-of-Windows-7_6BBADA1B.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="All of Windows 7" border="0" alt="All of Windows 7" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/1538.All-of-Windows-7_thumb_2103EC81.png" width="240" height="94" /></a>The original Code Canvas prototypes grouped all code files by their directory by default.  The groups were obviously hierarchical and often deeply nested, resulting in lots and lots of yellow folders surrounding each other.  Usually this was somewhat redundant since if you had a file named <span style="font-family: consolas">C:\Users\MyUser\Documents\Projects\Foo\Bar.cs</span> then we’d show Bar.cs surrounded by a yellow folder named “Foo”, which was surrounded by another yellow folder named “Projects”, surrounded by another folder named “Documents”, etc.  We eventually added the feature to automatically collapse this situation into a single yellow folder named “C:\Users\MyUser\Documents\Projects\Foo”.

<div style="clear: both"></div>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/0243.Groups_3BD0128D.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="Groups" border="0" alt="Groups" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/6835.Groups_thumb_39B313C4.png" width="240" height="143" /></a>You could also add your own groups and name them whatever you’d like.  The idea behind this was more than simply a means of controlling layout, it was also meant to provide a way to provide architectural context on the canvas.  For example, a common use case may be to have a group for “Model” code, “View” code, “ViewModel” code, etc.  The layout engine would make sure that items in one group would not be allowed in another, and that groups could not overlap unless they were strictly nested.  We did not have the ability at the time to have non-hierarchical grouping (e.g. Venn or Euler diagrams) but this is something that Code Canvas definitely needs to take full advantage of this idea.

<div style="clear: both"></div>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/5287.ExecutionTraceFewLayers_7488AF80.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="ExecutionTraceFewLayers" border="0" alt="ExecutionTraceFewLayers" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/6761.ExecutionTraceFewLayers_thumb_510C0B1B.png" width="240" height="172" /></a>The groups could also be turned on or off individually (which simply toggled the visibility of the background, label, and graphics) but the layout engine would always consider them when performing layout even if the graphics were not visible. This made it so toggling the visibility would not cause the layout to change, which was a good thing. Code Canvas has the ability to show many different aspects of the code and it was a design goal that changing the <em>display</em> of the code would not change the <em>layout</em> of the code. After all, we are attempting to leverage spatial memory to its fullest extent, and having everything jump around by simply changing the visibility of the graphics would be a bad thing.

<h2 style="clear: both">Annotations</h2>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/5224.Powerlaw-Scaling_56A70A33.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="Powerlaw Scaling" border="0" alt="Powerlaw Scaling" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/6204.Powerlaw-Scaling_thumb_48F44E2B.png" width="240" height="57" /></a>In addition to adding context to the canvas via grouping and named labels, we also had support for adding other basic annotations such as sticky notes and push-pins.  Sticky notes were rather rudimentary; you could type text in them and point an arrows from a sticky note to the items it was referring to, but that was about it.  The pushpins were simple but they were very useful as landmarks since they did not scale linearly with the rest of the canvas.  They used what is known as <a href="http://blogs.msdn.com/b/lutzg/archive/2008/11/03/powerlaw-scaling-of-synchronized-content-with-deep-zoom.aspx">power-law scaling</a> which essentially makes them shrink <em>slower</em> than the rest of the canvas so that you can always see them no matter how far you zoom out.

<h2 style="clear: both">Ambient Information</h2>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/3034.Win7HeatMapScreenshot5_1FAB7EA8.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="Win7HeatMapScreenshot5" border="0" alt="Win7HeatMapScreenshot5" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/8715.Win7HeatMapScreenshot5_thumb_46B6181D.png" width="240" height="175" /></a><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/6404.Highlighting_34DEEFDA.png"><img style="padding-left: 0px;padding-right: 0px;float: right;clear: both;padding-top: 0px;border-width: 0px" title="Highlighting" border="0" alt="Highlighting" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/4331.Highlighting_thumb_13131749.png" width="240" height="125" /></a>Most IDEs (or their add-on packages) have the ability to highlight code in the editor to display some kind of information (e.g. code coverage, test metrics, etc.).  Code Canvas also has this ability and it makes it even more useful by allowing you to zoom out and see the highlights across your entire codebase which can help you visually detect “problem areas” or “hot spots” if your code is arranged in a meaningful way.  Even when zoomed in you are still immersed in the ambient information with the highlighting all around you and the surrounding code.  Whether the ambient information represents code coverage, bug data, team activity/ownership, or anything else, you can be constantly surrounded by the information in real-time without having to switch tool windows or run separate tools.  This can act as an “augmented reality” for your code and help enable early problem detection and smarter software development.

<h2 style="clear: both">Control Structure and References</h2>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/2451.Control-Structure-Diagram_425A1D88.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="Control Structure Diagram" border="0" alt="Control Structure Diagram" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/4011.Control-Structure-Diagram_thumb_27414E7A.png" width="91" height="240" /></a><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/4505.ExecutionPaths_15B875A8.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="ExecutionPaths" border="0" alt="ExecutionPaths" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/3122.ExecutionPaths_thumb_5B5CFFC6.png" width="244" height="84" /></a>Code Canvas has the ability to overlay graphics other than simple highlighting.  One of the prototypes included Control Structure Diagrams drawn next to the code, and another integrated with <a href="http://research.microsoft.com/en-us/projects/pex/">Pex</a> to show all possible execution paths through the code, with the ability to show or hide individual paths.  Code Canvas also draws a link from an identifier to it’s definition whenever you click a floating icons or labels, or when the text cursor is on an identifier token.  When you select a range of text then you can see edges for all of the selected identifiers pointing to the things they reference.

<h2 style="clear: both">Off-Screen References</h2>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/4087.References_7141B530.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="References" border="0" alt="References" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/7128.References_thumb_27CF6075.png" width="240" height="172" /></a>When you are zoomed in far enough to select text then it’s likely that whatever that text references is going to be off the screen (unless you have an extremely small project or an extremely large monitor).  In this case Code Canvas shows a little preview on the edge of the screen (kind of like a floating rectangular magnifying glass) that gives you a preview of what the other end of the arrow points to.  Clicking on the preview “glass” automatically zooms you out from where you are and flies you to the area being shown in the preview at the same level of zoom.  This of course means the <em>source</em> of the arrow is now off the screen in the other direction, so you would then be left with a <em>new</em> preview glass that shows you a preview of where you just <em>were</em>.  You can quickly and easily navigate back and forth between two ends of an edge this way.

<h2 style="clear: both">Search Results</h2>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/0755.SearchResults_66C0E110.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="SearchResults" border="0" alt="SearchResults" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/0830.SearchResults_thumb_2250CA04.png" width="240" height="172" /></a>Another feature of Code Canvas is the ability to search and see results overlaid on top of the canvas.  This can provide more meaning than a traditional output window or list view, since it’s easy to see clusters of results and patterns of frequency in different areas of the codebase.  This is another case where it’s important to have a meaningful layout of the code rather than a temporary or automatically-generated layout, since if the locations of code don’t <em>mean</em> anything then the clusters and patterns seen will also not mean anything.  If, on the other hand, you organize your canvas into an architecturally meaningful design (for example, UI code in one section, business logic in another, data access in a third, etc.) then it will mean something when a majority of your search results appear in a certain area of the canvas instead of another.  Code Canvas even takes advantage of this spatial meaning when zoomed in by keeping off-screen search results snapped to the edge of the screen in the direction of the result.  This uses the same algorithm as the off-screen reference preview window, but instead of showing a preview window of the result it simply shows the search result in a semi-transparent way.  The transparency not only distinguishes it from an <em>actual</em> on-screen result, but it also allows multiple groups of results to “build-up” into a more solid, thicker blob indicating a high frequency of results in that direction.

<h2 style="clear: both">Execution Trace Playback</h2>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/1004.DetailedMultiExecutionTrace_359180A3.png"><img style="padding-left: 0px;padding-right: 0px;float: right;margin-left: 0px;margin-right: 0px;padding-top: 0px;border-width: 0px" title="DetailedMultiExecutionTrace" border="0" alt="DetailedMultiExecutionTrace" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/8863.DetailedMultiExecutionTrace_thumb_25A23BDF.png" width="237" height="240" /></a>One of the most well-received demos at TechFest was the ability to play back a recorded trace of a program’s execution and watch as the flow of control moved throughout the code on the canvas.  You can't tell from the picture, but the dashed lines actually animate along the execution path and you can control them with the slider(s) on top.  In the case of a multi-threaded program you will have multiple sliders (one per thread) which are linked by default so that when you drag one from left to right then the other will move automatically to match the execution as it executed in parallel.  When the sliders are linked this way then you are essentially dragging the slider “through time” and it’s easy to see how thread execution interleaves and interacts.  This is just the tip of the iceberg in this area.  We haven't even begun visualizing the data state that's associated with each thread, or what it looks like when there is a preemption in a thread, or how to tell what the "current" thread is (or current "threads" when you're running multicore), or lots of other things.

<h1 style="clear: both">Continuing Research</h1>
The original Code Canvas prototypes made for excellent demos and received internal and external acclaim, but several technological factors prevented us from being able to actually deploy and test it “in the field” on large codebases.  These are some of the things that we really need(ed) in order to continue the Code Canvas research and make it into something that can be tested in the field and used on a regular basis.

<h2 style="clear: both">Better Language Support</h2>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/0083.Figure1_6464A3DC.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="Two Classes" border="0" alt="Two Classes" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/3223.Figure1_thumb_22E9F183.png" width="400" height="263" /></a>C# 3.0 was the language of choice among our target audience at the time that Code Canvas was being developed, but our available compiler tools only supported up to C# 2.0 (and poorly at that). This was sufficient to generate some limited and contrived demos but it was not enough to fully demonstrate the concept of visualizing all links and relationships within the source code text as you type (shown by the blue lines in the figure). This is a key research area fundamental to Code Canvas but unfortunately we were unable to create prototypes to demonstrate it.  This is an even bigger issue now since web-based development never uses the same language throughout the project, and so we want to support a mix of JavaScript, JSON, HTML, XML, ASPX, VB, C#, F#, PHP, SQL, you-name-it.

<h2 style="clear: both">Visual Designers</h2>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/3113.Figure2_7AD74263.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="Designer and Handler" border="0" alt="Designer and Handler" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/5873.Figure2_thumb_27EC2F32.png" width="400" height="81" /></a>In order to be a fully immersive experience, Code Canvas needs to include visual designers such as WinForms, WPF, Silverlight, ASP.NET/HTML, etc. Not only is this necessary to keep the developer immersed within their spatial context, but also because a primary benefit of Code Canvas is the ability to see arrows pointing from tokens to whatever they refer to. When tokens refer to visual UI elements with no “real” code associated with them (other than auto-generated code by the designer) then we need to be able to display the UI element on the canvas to give the arrow somewhere to go. One example is the relationship between a button on a form and its code-behind “click” handler. Another example is when a piece of code references a textbox there should be a link pointing from the variable in the code to the textbox on the form.

<div style="clear: both"></div>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/6786.Designers_12810F33.png"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="Designers on Canvas" border="0" alt="Designers on Canvas" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/0841.Designers_thumb_15664E19.png" width="240" height="172" /></a>Our first attempt at integrating Code Canvas with Visual Studio gave us the ability to display WinForms-based designers on the same canvas as code editors, but the API did not give us access to the sub-elements on the form. This prevented us from drawing relationship/reference arrows to elements on the forms or even highlighting code fragments when their corresponding elements were selected. This somewhat nullified the effectiveness of displaying the two side-by-side and we never had the chance to research it accordingly.

<h2 style="clear: both">Inline Editing and Real-Time Updates</h2>
<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/6763.Figure0-blinking_7926768F.gif"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="Editing with Intellisense" border="0" alt="Editing with Intellisense" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/5466.Figure0-blinking_thumb_0D3F9319.gif" width="400" height="126" /></a>The crux of Code Canvas that differentiates it from other visualizations or diagramming tools is that it must support editing <i>on the canvas</i> so that the developer is constantly surrounded by the context of the surrounding code, the code’s relationships, and other ambient information about the software. Unfortunately, the original prototypes of Code Canvas did not allow editing at all because it was a standalone application and no code editors outside of Visual Studio were available at the time. When Visual Studio 2010 came out we attempted to integrate Code Canvas with it but editing was slow and several issues with the Visual Studio SDK prevented us from providing a desirable enough experience to confidently deploy internally or test in the lab.

We also need to explore the possible ways of dealing with elided, occluded, or hidden code is.  For example, code surrounded by <span style="font-family: consolas, courier"><span style="color: blue">#region</span></span> is can be “collapsed” in the traditional editor, but what does this mean on the canvas?  One of the great benefits of the canvas is <strong>tractability</strong>, meaning you can simply zoom out to get a visual representation of “how much code exists in this project” and be assured that “if I read through all of this code laid out before me then there will be nothing left that I don’t know about”.  If we give the ability to collapse or <em>hide</em> code then that confidence can no longer be trusted and new developers will never be sure that they won’t run into some tiny piece of collapsed code that explodes into another huge area to learn.

Even if you ignore the issue of tractability (which you shouldn’t), what should expanding/collapsing the code do to the layout of the code that surrounds it?  By clicking the innocent-looking +/- box next to the code you have the potential of pushing all sorts of adjacent code out of the way since we don’t allow overlaps.  This may be better suited to the “filtered views” described below.

<h2 style="clear: both">Better Layout and Edge Routing</h2>
<a href="http://research.microsoft.com/en-us/um/people/nath/EulerDiagrams/"><img style="padding-left: 0px;padding-right: 0px;float: right;padding-top: 0px;border-width: 0px" title="Non-hierarchical Groups" border="0" alt="Non-hierarchical Groups" align="right" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/2287.Non-hierarchical-Groups_56B85E8E.png" width="240" height="186" /></a>Real-time layout and edge routing is critical for Code Canvas, and we are fortunate to have Microsoft Automatic Graph Layout (MSAGL ) to help with this. MSAGL had just added support for Fast Incremental Layout when we were creating the first Code Canvas prototypes, and performance was good enough to give demos, but it was too slow to support real-sized code projects and several features were missing that Code Canvas needed. For example it lacked support for concave group/node geometry, non-hierarchical overlapping group layout, snap-based/grid-based node layout, rectilinear edge routing, edge labels, etc.  One thing that it <em>did</em> have is the ability to specify “constraints” on the layout, for example you could create a rule that super-classes must be above sub-classes by saying that all inheritance edges must point downwards (or upwards, depending on if you’re coming from UML or not).  You could also specify alignment constraints, for example you could force the tops, middles, or bottoms of code fragments to be aligned, and when you drug one fragment around then the other fragments would follow to ensure the constraints were not broken.  Unfortunately we didn’t get a chance to test this in the field or explore the best way to expose this functionality to the user.

<h2 style="clear: both">Semantic Annotations and “Hand-Drawings”</h2>
The original prototype briefly touched on the ability to add annotations and landmarks, but it was never really studied and it never had the ability to “draw” next to or around code.  It seems intuitive that any canvas-based environment should have the ability to draw a border around a bunch of items to form a group, or that you should be able to scribble a comment and draw an arrow to the thing you’re talking about.  But what does it mean when we zoom in and out?  In traditional ZUIs (ranging all the way from modern-day <a href="http://prezi.com/">Prezi</a> back to the original <a href="http://www.cs.umd.edu/hcil/pad++/">Pad++</a>), you wind up scaling the annotation equally with the rest of the content and you’re left with either gigantic pen strokes taking up your entire screen or teeny tiny pixels that you might not even know are there.  <a href="http://dub.washington.edu:2007/projects/denim/">Denim</a> improves on this with it’s semantic zoom but will it scale to a real system or work well with text-based code fragments?  It’s also unclear where to draw the line between annotating directly on the canvas vs. simply linking to content in a new window.  For example, text and illustrative drawings probably belong directly on the canvas but an embedded video might be better off opening in a separate window.

<h2 style="clear: both">Task-Specific and Filtered Views</h2>
The buzz around Code Bubbles and the success of Debugger Canvas makes it clear that a whole-system view where everything is on the canvas at once is not always what you want.  When you have a very focused task to do it may be desirable to filter the canvas to only those portions relevant to your current task.  But how can we do this in a way that maximizes reuse of your already-built spatial memory, and keeps you oriented in the context of your system even though the rest of the system is no longer visible?  We experimented a bit with what we called “filtered canvases” when we attempted to integrate Code Canvas with Visual Studio, but we didn’t have enough technology available to actually test what we wanted in the field.

<h2 style="clear: both">Minimap(s) and Extra Views</h2>
Video games that involve panning have had minimaps since the dawn of time, but it’s unclear whether they are needed when zooming is supported too.  Minimaps also have the choice of being a “dumbed-down” representation of the <em>actual</em> surface (e.g. representing each item as a single pixel or icon in the minimap), or being a realistic scaled-down version of the surface instead. When semantic zoom is involved then a minimap might actually be both at once, since the semantically zoomed-out version of items might actually be a single icon instead).  In other words, the minimap might simply show exactly what the real surface would show if the user zoomed all the way out.  In this case, the minimap is simply an <em>extra view</em> that is simply smaller and docked in a corner of the window, with the extra addition of having a little rectangle that represents the viewport on the <em>actual</em> surface.  There’s should be nothing stopping the extra view from being hosted outside the original window, perhaps on a secondary monitor, and if it were maximized then you would essentially have two large, detailed views on the same surface at once.  Each one could contain “little rectangles” that represents where the other view(s) are looking, and thus the original “minimap” is just one particular configuration of the capability of having more than one view in general.

<h2 style="clear: both">Navigation and Key-Bindings</h2>
Being able to use spatial memory to navigate code makes it much harder to “get lost in your code”, but it’s not impossible.  Especially if you’re frequently using the off-screen preview windows or clicking on search results to “fly” across the canvas, you will most certainly want a way to go <em>back</em> to where you just were (just like in a web browser).  I have a 5-button mouse and it’s extremely convenient to use the extra buttons to navigate backwards and forwards.  The only question is of how fine-grained the buttons should be.  For example, if I’ve used the arrow keys to move the cursor up and down the code, the forward- and back-buttons should probably not move me back and forward one line at a time.  But if I used PageUp and PageDown instead of the arrows keys then perhaps they should.  If I double-clicked on a search result or preview window then I should <em>definitely</em> be able to click the back-button and fly back to where I came from, but if I got there manually by zooming and panning the canvas by hand then it’s not so clear.

We’ve also done some work experimenting with the best way to use the keyboard to navigate from one code fragment (or item) to another, but it’s still confusing to use Up/Down/Left/Right to navigate essentially a <em>graph</em> where items are not necessarily aligned in a grid-like fashion.  We know that most programmers find it too time consuming to lift their hands off the keyboard in order to use the mouse, so being able to navigate throughout the canvas using the keyboard is important.  (No, we <em>don’t</em> suggest that software development should be done using an Xbox controller.)

<h2 style="clear: both">General User Experience</h2>
Code Canvas has a <em>ton</em> of information layered on top of a huge (infinite) zoomable surface.  Making it all user-friendly, visually appealing, and non-overwhelming is a constant exercise in user experience design.  There are several additional techniques that we would like to implement and test, for example:
<ul>
 	<li>Search results are currently all shown individually.  When zoomed in, the results that are off the screen are semi-transparent and when they overlap they combine to become more opaque.  But search results can also overlap when zooming <em>out </em>since content gets closer and closer together, and translucency is not really appropriate in that case.  Instead, multiple overlapping search results should coalesce into a single ‘blob’ that shows an aggregate of the results.  The coalescence should happen dynamically and fluidly as the user zooms in and out instead of simply <em>snapping</em> from one representation to another.</li>
 	<li>Groups look nice when zoomed out large enough to see the entire group; you can see their entire border and label at the top.  But when zooming into something <em>within</em> the group, the border and label are often off the edge of the screen and you can no longer tell which group(s) you are in.  We should use some visual effects to keep the group borders/labels constrained to the edge of the screen (just like search results are).  If there are several groups surrounding the current view (e.g. a deeply nested hierarchy) then we should attempt to combine their visual representation into a single border/label that aggregates their purpose.</li>
 	<li>We currently use simple pastel-colored highlighting to represent things like code coverage, but when it comes to things like error-prone code (that is, code which has had multiple bugs filed against it) or high-churn code (code which has had multiple checkins or checkins from multiple people) or cloned-code etc., it may be more appropriate to use game-like graphics like green wafts of “stink” or tiny “bugs” crawling around the code.  This would be more than just <em>fun</em>, it may also be a sort of social conditioning to help developers instinctively avoid writing “bad code” for fear of their section of code looking like garbage.  Likewise, perhaps very good code should have a glow or other pleasing affect applied to it in order for the author to “show off” his expert coding skills whenever someone zooms out to see the entire codebase at large.</li>
 	<li>Some users have expressed that zooming in and out to see details is overwhelming and some even report motion sickness.  Perhaps a good option for these users is a way to have a “magnifying glass” or “pop-up editors” so that the user can stay mostly zoomed out all the time but enlarge specific areas to see details or edit code.  The challenge then becomes how to deal with the pop-ups if they last for any significant amount of time.  For example, a section of the canvas is magnified or “popped-up” and you pan the canvas beneath it, should the popups move as well?  Or should they stationary on the screen?  And when a code editor is “popped-up”, should you be able to scroll up and down within it?  Perhaps even be able to pan side-to-side in it?  Should a pop-up be able to show more than one item at a time?  These are the types of questions that we have yet to explore and research, and our primary goal is to find whatever is optimal for software developers and software development instead of solving the problem for ZUIs in general (but of course we will be pleased if our research benefits other ZUIs as well).</li>
</ul>

<h2 style="clear: both">Ease of Getting Started</h2>
Even if the original Code prototypes were fully functional and scaled to real code, we never determined the best way to “get started” using Code Canvas. Our original target audience – internal Microsoft developers – has large amounts of pre-existing and legacy code. In the standalone prototype, the workflow was to click File -&gt; Import and point it to a .sln or .csproj file and it would do a one-time import of the code. The user would then have to wait for the import to finish which could take a very long time on nontrivial projects.

It’s also unclear whether it is best to start out by “dumping the entire codebase onto the canvas” instead of allowing (forcing?) the developer to selectively choose which pieces to incrementally add to the canvas by hand. If we dump the entire codebase onto the canvas, how should it be laid out? Preliminary work was done to develop a fixed-size leaf node tree map algorithm but it still needs work to support predefined group hierarchies.

<h1 style="clear: both">New and Unexplored Research Areas</h1>
In addition to the features already prototyped and demonstrated, there are still several new areas and aspects we’d like to research and explore.  Here are just a few.

<h2 style="clear: both">Cross-Solution, Distributed System, and Dependency Layering</h2>
Software inevitably makes use of external libraries and is typically structured into “layers” of dependencies either intra-project or inter-project. Typically the references between layers are unidirectional but widespread. For example, consider the .NET framework. All .NET programs have a reference to the .NET framework, and it may be useful to visualize which areas of code reference which areas of the .NET framework (e.g. perhaps only a certain area of user code should access the System.IO or System.Net namespaces in order to maintain a sandbox level of security). It may be visually meaningful to organize one’s user code on the canvas to roughly match the areas of functionality in the framework. For example, consider the following sketch showing an ASP.NET web app that generates visualizations from files on disk. The file access code is on the far left of the canvas, the HTML web page code on the far right of the canvas, and the image loading and visualization generation code is in the middle.

<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/5340.Figure3_0E00598C.png"><img style="padding-left: 0px;padding-right: 0px;padding-top: 0px;border-width: 0px" title="User-Code Floating Above Framework Code" border="0" alt="User-Code Floating Above Framework Code" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/38/55/metablogapi/1121.Figure3_thumb_3A7963A5.png" width="1024" height="392" /></a>

In this case there are only two “layers” of dependency: 1) the application code seen on top, and 2) the framework code shown below. .NET programs can become more complex with multiple layers of dependency (for example if this program used the Entity Framework, which ships separately and on top of the .NET Framework, then it would sit “between” the user code layer and the .NET Framework code layer. Programs can also contain internal layers or aspects which may be ideal to visualize in this pseudo-3D kind of way. For example a program may contain logging code that is accessed throughout the entire codebase, and rather than showing many arrows overlapping on the same plane as the rest of the user code, it may be desirable to show the logging code “underneath” the rest of the user code instead.

In the case of the .NET Framework (and in fact also with the Entity Framework and most other frameworks by Microsoft), the libraries are read-only monolithic packages that can essentially be treated as black boxes. They are of high quality and maintained by Microsoft, so in the example above there is not much need to zoom into the .NET framework to view its source code (unless debugging of course), and one might question the value of being able to do so in Code Canvas. But when dealing with open-source and highly segmented but interconnected libraries (jQuery.js, Knockout.js, Hammer.js, Sigma.js, Smoke.js, Envision.js, to name a few) the ability to drill into and even modify the libraries in-place becomes more and more important as the web of dependencies in the software community becomes more and more complex.

<h2 style="clear: both">Team Activity and Ownership</h2>
In traditional corporate-based software development where all team members work in the same hallway it’s fairly easy to know who’s working on what and who’s responsible for a particular piece of code or functionality.  But what can we do in the world of open-source development and crowdsourcing?  Not only do we want to explore how we can use the canvas to help in this area (such as color coding areas of the code based on ownership, or drawing “fences” around “territory”, or showing thumbnail portraits of other developers on the edge of the screen when they are actively editing code nearby), but what should be done about the ownership of the canvas itself?  Who decides how the software should be laid out and what the architectural boundaries should be?  Should it be possible for every developer to be moving code around and re-arranging it at once?  Certainly this would be very confusing to one developer if someone else moves his code “out from under him” while he’s working on it!  Since the relative positioning of code and artifacts has <em>meaning</em> in the overall system, perhaps layout changes should not be made without consensus.  But even if a single benevolent dictator owns the layout of the canvas and it’s read-only to everyone else, it still be possible for individual contributors to add annotations and illustrative drawings to the canvas, right?  We know from experience that meaningful layout of diagrams and code is useful and is usually shared across a team, but we haven’t had the opportunity to study what the best method of sharing is in this type of interactive real-time immersive environment.

<h2 style="clear: both">Data Flow Analysis and Visualization</h2>
The current prototypes of Code Canvas have shown some examples of static reference visualization, control flow visualization, and even the ability to record &amp; playback execution traces, but there has been no work done on visualizing data flow. This is especially important in the world of JavaScript and the DOM since these loosely typed languages are based entirely on the instances of objects and data values that are passed throughout the system. The canvas should be able to draw a data trace – either statically using code analysis/inference or dynamically at runtime – that shows how a piece of data travels and gets mutated throughout the codebase. This would enable developers to answer questions such as “An invalid value is being passed to a method; where did this value come from and how did the value become what it is?”, and “Can I guarantee that the arguments being passed to my function will always be non-null?”, and “Where are all the places that data can come from that can eventually get passed here?”

<h2 style="clear: both">Runtime Heap &amp; Object Graph Visualization</h2>
The 2D canvas works well for displaying static code since there is only one “copy” of the code to display, but how can we show several “instances” of the code at runtime while still maintaining the spatial context and layout of the canvas? Should we show several instances of the code itself (which would be very straightforward and easy to understand, but wastes a lot of screen real-estate), or just show the data values contained by each instance instead? Should 3D be used here, and if so then how would it coincide with other uses of 3D such as the layered view shown above? It seems obvious that the spatial layout of the code on the canvas should be re-used and preserved as much as possible in order to take advantage of spatial memory when displaying runtime heap data and object graphs, but the exact visualization of the scenario is a research area that needs much more exploration.

<h2 style="clear: both">Comparing “Diffs” of Code and Changes Over Time</h2>
In the ever-changing world of open-source it becomes more important than ever to track and understand code changes and see how a code base is changing over time. In traditional bento box IDEs this is accomplished by comparing one file at a time and typically opening a new window that shows the two files side-by-side or interleaved line-by-line. This may not be the best approach when using the canvas, since 1) showing a code fragment to the side of an existing one would end up physically colliding or overlapping any source code adjacent to it, and 2) it should also be useful to see the differences in the <i>relationships</i> between code and how the layout of the code on the canvas changes over time as well. This is an area that needs to be explored further so that the user does not need to escape from the canvas in order to view diffs and code changes using external programs.]]></content:encoded>
    </item>
    <item>
      <title>Code Canvas vs. Code Bubbles vs. Debugger Canvas</title>
      <link>https://docs.microsoft.com/archive/blogs/kaelr/code-canvas-vs-code-bubbles-vs-debugger-canvas</link>
      <pubDate>Sat, 10 Mar 2012 18:35:00 GMT</pubDate>
      <dc:creator><![CDATA[Kael Rowan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaelr/2012/03/10/code-canvas-vs-code-bubbles-vs-debugger-canvas/</guid>
      <description><![CDATA[You may have seen my previous comparison of Code Canvas vs. Diagrams/Visualizations, but sometimes...]]></description>
      <content:encoded><![CDATA[<p>You may have seen my previous comparison of <a href="http://blogs.msdn.com/b/kaelr/archive/2009/04/05/code-canvas-vs-diagrams-visualizations.aspx">Code Canvas vs. Diagrams/Visualizations</a>, but sometimes people also ask me “What is the relationship between Code Canvas and Debugger Canvas?”, or “Is Debugger Canvas the same as Code Bubbles?”.&#160; Here are my personal thoughts on some of the high-level differences between the three:</p>  <p><a href="http://research.microsoft.com/en-us/projects/codecanvas/"><strong>Code Canvas</strong></a>: Shows source code and relationships among source code on a zoomable canvas in a spatially stable and meaningful way. It allows code to be edited directly on the canvas instead of in separate tabbed editors like traditional IDEs. Semantic zoom is used to zoom out to view the entire system and its architecture in a smooth “deep zoom” kind of way. Information overlays like references, code coverage, and execution traces are displayed directly within the canvas instead of a separate diagram or window. The position of each item on the canvas has <i>meaning</i> in the context of the overall software diagram and is not placed arbitrarily. Each item on the canvas has one and only one location and is never duplicated (although it can be moved). Development teams share and collaborate over a single master canvas in the same way they agree on the locations of files in their source control directory tree. The lifetime of the canvas is mostly expected to be permanent and become a valued asset of the project. Spatial memory is a primary focus.</p>  <p><a href="http://www.andrewbragdon.com/codebubbles_site.asp"><strong>Code Bubbles</strong></a>: Replaces the entire IDE with a single canvas. It contains source code fragments but also can contain tool windows, property grids, tear-off queries, work items, email, etc. Some windows (like menus or property grids) may appear just temporarily in a spatial radius around the “current item” instead of always being visible on the canvas. The position of each item on the canvas is meant to maximize organization or screen real-estate for the current task or environment. Items (including source code fragments) can be duplicated and appear in multiple places at once. Development teams may give copies of canvases to team-mates or new hires but they are usually developer-specific. The lifetime of the canvas is usually temporary and/or task-specific. Spatial memory may be relevant but is not a primary focus.</p>  <p><a href="http://msdn.microsoft.com/en-us/devlabs/hh227299"><strong>Debugger Canvas</strong></a>: Shows source code fragments on a canvas for each step of a program being debugged, with arrows indicating where one method stepped into another during that debugging session. It also contains non-code items such as “locals” windows on the canvas and allows debugging-specific operations such as taking a snapshot of the local variables. The position of each item on the canvas is related directly to the order (or thread) in which it was called during a debugging session. The user has the option of duplicating source code fragments on the canvas each time the code is stepped into, or they can choose to reuse the same fragment over and over if it is called more than once. Developers may send static screenshots or copies of the canvas to teammates but otherwise canvases are not shared. The lifetime of the canvas is only meant to last for a single debugging session. Spatial memory is only a focus in that it is meant to be consistent with the order of execution of the program.</p>]]></content:encoded>
    </item>
    <item>
      <title>Debugger Canvas 1.1 is Released!</title>
      <link>https://docs.microsoft.com/archive/blogs/kaelr/debugger-canvas-1-1-is-released</link>
      <pubDate>Tue, 31 Jan 2012 10:57:19 GMT</pubDate>
      <dc:creator><![CDATA[Kael Rowan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaelr/2012/01/31/debugger-canvas-1-1-is-released/</guid>
      <description><![CDATA[Hi everyone, we are pleased to announce the release of Debugger Canvas version 1.1. This version...]]></description>
      <content:encoded><![CDATA[<p>Hi everyone, we are pleased to announce the release of <a href="http://msdn.microsoft.com/en-us/devlabs/debuggercanvas">Debugger Canvas version 1.1</a>. This version includes a number of bug fixes, new features, and improves performance. Some of the new features are:</p>  <p>- Easily turn Debugger Canvas on or off, even in the middle of a debug session.    <br />- Quickly navigate up and down the call stack in the canvas using the keyboard or the mouse.    <br />- See Multiple threads together on the canvas, each thread identified by its color.     <br />- See recursive calls side by side.     <br />- The option to edit code directly in the code bubbles is enabled by default.</p>  <p>This last &quot;feature&quot; is actually nothing new. You could always edit code directly in bubbles by checking the checkbox in Tools -&gt; Options, but some users didn't know that option existed so we frequently heard the feedback that you wished you could edit code directly in the bubbles. This time we just simply enable that feature by default if you're installing Debugger Canvas for the first time.</p>  <p>To install this updated version of Debugger Canvas you must <strong>uninstall</strong> the previous version of Debugger Canvas first. (Or install <a href="http://support.microsoft.com/kb/2581019">QFE 2581019</a> from <a href="http://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=38654">http://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=38654</a> before installing the update.) This is because Visual Studio 2010 SP1 has a bug which prevents signed VSIXes from being updated. I will also post a <a href="http://social.msdn.microsoft.com/Forums/en-US/debuggercanvas">sticky thread in the forum</a> since I'm sure many of you will attempt to install version 1.1 on top of 1.0 without reading the instructions first. I would do the same thing! :)</p>  <p>You can read more about the new version and read the updated guide from the usual home page here:   <br /><a href="http://msdn.microsoft.com/en-us/devlabs/debuggercanvas">http://msdn.microsoft.com/en-us/devlabs/debuggercanvas</a></p>  <p>Or you can skip straight to the download and get the VSIX directly from here:   <br /><a href="http://download.microsoft.com/download/5/A/7/5A7FB2E7-5720-4739-BDDE-28A684C5B291/Microsoft.DebuggerCanvas.vsix">http://download.microsoft.com/download/5/A/7/5A7FB2E7-5720-4739-BDDE-28A684C5B291/Microsoft.DebuggerCanvas.vsix</a></p>  <p>Thanks to everyone for their continued support and we sincerely hope you enjoy Debugger Canvas version 1.1!</p>]]></content:encoded>
    </item>
    <item>
      <title>Debugger Canvas Available for Download!</title>
      <link>https://docs.microsoft.com/archive/blogs/kaelr/debugger-canvas-available-for-download</link>
      <pubDate>Mon, 13 Jun 2011 17:01:00 GMT</pubDate>
      <dc:creator><![CDATA[Kael Rowan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaelr/2011/06/13/debugger-canvas-available-for-download/</guid>
      <description><![CDATA[I&rsquo;m pleased to announce that Debugger Canvas is available for download on DevLabs!&nbsp;...]]></description>
      <content:encoded><![CDATA[<p>I&rsquo;m pleased to announce that <a href="http://msdn.microsoft.com/en-us/devlabs/debuggercanvas">Debugger Canvas</a> is available for download on <a href="http://msdn.microsoft.com/en-us/devlabs/debuggercanvas">DevLabs</a>!&nbsp; Debugger Canvas is a Power Tool for Visual Studio 2010 SP1 that pulls together the code you&rsquo;re exploring onto a single pan-and-zoom display. As you hit breakpoints or step into code, Debugger Canvas shows just the methods that you&rsquo;re debugging, with call lines and local variables, to help you see the bigger picture.&nbsp; See my previous post <a href="http://blogs.msdn.com/b/kaelr/archive/2011/05/21/introducing-debugger-canvas.aspx">Introducing Debugger Canvas</a> for the demo video.</p>
<p>We&rsquo;ve heard you loud and clear that you wish Debugger Canvas wasn&rsquo;t Ultimate-only.&nbsp; We would love to make Debugger Canvas available to a wider audience, but as <a href="http://blogs.msdn.com/b/somasegar/archive/2011/06/13/debugger-canvas-on-devlabs.aspx">Soma says on his blog</a>, Debugger Canvas is built on top of Visual Studio Ultimate so that we could re-use the underlying technology for the <a href="http://msdn.microsoft.com/en-us/library/dd409453.aspx">Dependency Diagrams</a> to identify and display the right fragments on the canvas.&nbsp; This re-use is what made it possible for us to release an out-of-band power tool in an efficient manner on top of Visual Studio 2010.&nbsp; It's unlikely that we'll be able to make this version of the power tool available in Pro, but please let us know if you'd like to see this kind of user experience built directly "in the box" as part of Visual Studio. </p>
<p>In the mean time, if you don&rsquo;t have Visual Studio Ultimate then you still have two options to try Debugger Canvas for free:</p>
<p>1) Install the free <a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=e2a1a098-995e-4468-816d-7fdbe0a64f38&amp;displaylang=en">Visual Studio Ultimate Trial</a>, or <br />2) Install the free <a href="http://blogs.msdn.com/b/briankel/archive/2010/06/25/now-available-visual-studio-2010-rtm-virtual-machine-with-sample-data-and-hands-on-labs.aspx">Virtual Machine containing Visual Studio Ultimate</a>.</p>
<p>The second option is probably the most convenient since Visual Studio Ultimate is already pre-installed on the machine.&nbsp; All you need to do is copy the <a href="http://download.microsoft.com/download/5/A/7/5A7FB2E7-5720-4739-BDDE-28A684C5B291/Microsoft.DebuggerCanvas.vsix">Debugger Canvas VSIX</a> into the virtual machine and install it.</p>
<p>Please send us your questions and feedback on the <a href="http://social.msdn.microsoft.com/Forums/en-US/debuggercanvas/threads">Debugger Canvas DevLabs Forum</a>.&nbsp; Thanks!</p>]]></content:encoded>
    </item>
    <item>
      <title>Introducing Debugger Canvas</title>
      <link>https://docs.microsoft.com/archive/blogs/kaelr/introducing-debugger-canvas</link>
      <pubDate>Sat, 21 May 2011 13:12:00 GMT</pubDate>
      <dc:creator><![CDATA[Kael Rowan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaelr/2011/05/21/introducing-debugger-canvas/</guid>
      <description><![CDATA[Over the past several months I’ve been working on a new Power Tool for Visual Studio with Andrew...]]></description>
      <content:encoded><![CDATA[<p>Over the past several months I’ve been working on a new Power Tool for Visual Studio with <a href="http://www.andrewbragdon.com/">Andrew Bragdon</a> and <a href="http://www.cs.brown.edu">Brown University</a>.&#160; The purpose of the power tool is to get feedback from users (that means you!) about using a <a href="http://www.cs.brown.edu/people/acb/codebubbles_site.htm">Code Bubbles</a> like experience for debugging through code inside Visual Studio.&#160; The Power Tool will be called Debugger Canvas and will be available for download on Microsoft <a href="http://msdn.microsoft.com/devlabs/">DevLabs</a> early next month.&#160; It will require Visual Studio 2010 Ultimate SP1 (or the <a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=e2a1a098-995e-4468-816d-7fdbe0a64f38&amp;displaylang=en">trial version</a>), and there will be a DevLabs forum for public feedback, discussion, questions and answers, etc.&#160; In the mean time you can find out more information on <a href="http://research.microsoft.com/debuggercanvas">http://research.microsoft.com/debuggercanvas</a> and also watch the demo video below.</p>  <P> <OBJECT width=533 height=325><PARAM NAME="movie" VALUE="https://www.youtube.com/v/3p9XUwIlhJg&amp;hl=en&amp;fs=1&amp;rel=0&amp;fmt=22&amp;ap=%2526fmt%3D22"><PARAM NAME="allowFullScreen" VALUE="true"><PARAM NAME="allowscriptaccess" VALUE="always"> <embed src="https://www.youtube.com/v/3p9XUwIlhJg&amp;hl=en&amp;fs=1&amp;rel=0&amp;fmt=22&amp;ap=%2526fmt%3D22" mce_src="https://www.youtube.com/v/3p9XUwIlhJg&amp;hl=en&amp;fs=1&amp;rel=0&amp;fmt=22&ap=%2526fmt%3D22" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="533" height="325"></embed></OBJECT></P>]]></content:encoded>
    </item>
    <item>
      <title>ZoomableApplication3: When not to ApplyTransform</title>
      <link>https://docs.microsoft.com/archive/blogs/kaelr/zoomableapplication3-when-not-to-applytransform</link>
      <pubDate>Wed, 18 Aug 2010 21:02:00 GMT</pubDate>
      <dc:creator><![CDATA[Kael Rowan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaelr/2010/08/18/zoomableapplication3-when-not-to-applytransform/</guid>
      <description><![CDATA[By default, ZoomableCanvas works by coercing its RenderTransform to be a combination of a...]]></description>
      <content:encoded><![CDATA[<p>By default, <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2010/07/29/zoomablecanvas.aspx">ZoomableCanvas</a></span></span> works by coercing its <span style="font-family: Consolas, Courier;">RenderTransform</span> to be a combination of a <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ScaleTransform</span></span> and a <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">TranslateTransform</span></span>&nbsp; representing the current <span style="font-family: Consolas, Courier;">Scale</span> and <span style="font-family: Consolas, Courier;">Offset</span>, respectively.&nbsp; This is the most performant mode in WPF, and makes your <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">UIElement</span></span>s scale up and down for free, but sometimes you can get better effects without the transform.&nbsp; If you set <span style="font-family: Consolas, Courier;">ApplyTransform = <span style="color: blue">false</span></span>, then <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2010/07/29/zoomablecanvas.aspx">ZoomableCanvas</a></span></span> will <em>position</em> your elements in the correct place as you zoom in and out, but it won&rsquo;t <em>scale</em> or <em>resize </em>them.&nbsp; It will be up to your <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">UIElement</span></span>s to respond to the changes in <span style="font-family: Consolas, Courier;">Scale</span> themselves, for example by changing their <span style="font-family: Consolas, Courier;">Width</span> and <span style="font-family: Consolas, Courier;">Height</span>, or changing their shape/template (e.g. <a href="http://www.infovis-wiki.net/index.php/Semantic_Zoom">semantic zoom</a>), or by even just ignoring it altogether.</p>
<p>To show you an example, I&rsquo;m going to start with the <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/04/90/70/ZoomableApplication2.zip" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Components-PostAttachments/00-10-04-90-70/ZoomableApplication2.zip">ZoomableApplication2</a> from the <a href="http://blogs.msdn.com/b/kaelr/archive/2010/08/11/zoomableapplication2-a-million-items.aspx">last post</a>, but I&rsquo;m going to modify it slightly by setting the <span style="font-family: Consolas, Courier;"><span style="color: blue">Padding</span></span> to&nbsp;<span style="font-family: Consolas, Courier;"><span style="color: blue">0</span></span>&nbsp;in the <span style="font-family: Consolas, Courier;"><span style="color: #a31515">ItemContainerStyle</span></span> and adding <span style="font-family: Consolas, Courier;"><span style="color: red">Stroke</span><span style="color: blue">="Black"</span></span> to the <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Rectangle</span><span style="color: blue">&gt;</span></span>s and <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Ellipse</span><span style="color: blue">&gt;</span></span>s (to give them a black outline).&nbsp; If you haven&rsquo;t read that post yet, you might want to do so now.</p>
<p>Next, I&rsquo;m going to set <span style="font-family: Consolas, Courier;"><span style="color: red">ApplyTransform</span><span style="color: blue">="False"</span></span> and modify the <span style="font-family: Consolas, Courier;"><span style="color: blue">Width</span></span> and <span style="font-family: Consolas, Courier;"><span style="color: blue">Height</span></span> setters in the <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox.ItemContainerStyle</span><span style="color: blue">&gt;</span></span> to multiply them by the <span style="font-family: Consolas, Courier;"><span style="color: blue">Scale</span></span> of the <span style="font-family: Consolas, Courier;"><span style="color: blue">ZoomableCanvas</span></span>, like this:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="Width"&gt;
    &lt;</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">MultiBinding </span><span style="color: red">Converter</span><span style="color: blue">="{</span><span style="color: #a31515">x</span><span style="color: blue">:</span><span style="color: #a31515">Static </span><span style="color: red">ArithmeticConverter</span><span style="color: blue">.Default}"
                      </span><span style="color: red">ConverterParameter</span><span style="color: blue">="*"&gt;
            &lt;</span><span style="color: #a31515">Binding </span><span style="color: red">Path</span><span style="color: blue">="width"/&gt;
            &lt;</span><span style="color: #a31515">Binding </span><span style="color: red">Path</span><span style="color: blue">="Scale"
                     </span><span style="color: red">RelativeSource</span><span style="color: blue">="{</span><span style="color: #a31515">RelativeSource
                                      </span><span style="color: red">AncestorType</span><span style="color: blue">=ZoomableCanvas}"/&gt;
        &lt;/</span><span style="color: #a31515">MultiBinding</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">Setter</span><span style="color: blue">&gt;

&lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="Height"&gt;
    &lt;</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">MultiBinding </span><span style="color: red">Converter</span><span style="color: blue">="{</span><span style="color: #a31515">x</span><span style="color: blue">:</span><span style="color: #a31515">Static </span><span style="color: red">ArithmeticConverter</span><span style="color: blue">.Default}"
                      </span><span style="color: red">ConverterParameter</span><span style="color: blue">="*"&gt;
            &lt;</span><span style="color: #a31515">Binding </span><span style="color: red">Path</span><span style="color: blue">="height"/&gt;
            &lt;</span><span style="color: #a31515">Binding </span><span style="color: red">Path</span><span style="color: blue">="Scale"
                     </span><span style="color: red">RelativeSource</span><span style="color: blue">="{</span><span style="color: #a31515">RelativeSource
                                      </span><span style="color: red">AncestorType</span><span style="color: blue">=ZoomableCanvas}"/&gt;
        &lt;/</span><span style="color: #a31515">MultiBinding</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">Setter</span><span style="color: blue">&gt;</span></span></pre>
<p>Notice I&rsquo;m using my trusty <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2008/06/11/arithmeticconverter.aspx">ArithmeticConverter</a></span></span> from <a href="http://blogs.msdn.com/b/kaelr/archive/2008/05/21/presentation-more.aspx">Presentation.More</a> to do the multiplication (since XAML doesn&rsquo;t support math directly).&nbsp; This has the effect of simply <em>resizing</em> the shapes instead of <em>scaling</em> them, but it does nothing to the <span style="font-family: Consolas, Courier;"><span style="color: red">StrokeThickness</span></span> or the <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">TextBlock</span><span style="color: blue">&gt;</span></span> inside.&nbsp; Here are the results side-by-side, with <span style="font-family: Consolas, Courier;"><span style="color: red">ApplyTransform</span><span style="color: blue">="True"</span></span> on the left and <span style="font-family: Consolas, Courier;"><span style="color: red">ApplyTransform</span><span style="color: blue">="False"</span></span> on the right:</p>
<p><iframe width="525" src="http://research.microsoft.com/en-us/um/people/kaelr/apps/ZoomableApplication3-1.xbap" height="350"></iframe><br /><span style="font-size: xx-small;">(I&rsquo;ve embedded the sample as an XBAP in an <span style="font-family: Consolas, Courier;">&lt;iframe&gt;</span> above this line, so you should see a live sample and be able to interact with it if you&rsquo;re using Internet Explorer and have .NET 4.0 installed.)</span></p>
<p>Notice as you zoom out that it becomes hard to see the black outline around the shapes on the left, but the shapes on the right always maintain the same thickness.&nbsp; The same is true for the curvy paths.&nbsp; Also notice how the text labels on the left quickly become too small to see, but the labels on the right are always visible until clipped.</p>
<p>Another situation when to set <span style="font-family: Consolas, Courier;"><span style="color: red">ApplyTransform</span><span style="color: blue">="False"</span></span> is when you want certain items to scale at a different rate than the rest of the canvas.&nbsp; For example, say you want to be able to add flags or pushpins as landmarks on your canvas, but you don&rsquo;t want them to become too small when you zoom all the way out.&nbsp; In this case, you&rsquo;ll still be applying a <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ScaleTransform</span></span> to your items, but each item will have an individual transform instead of sharing one big one.&nbsp; This is because the <em>location</em> of your landmarks will be changing at a different rate than the <em>scale</em> of the landmarks, so the scene as a whole does not transform uniformly.</p>
<p>To add an overlay with landmarks on top of the canvas, I&rsquo;m just going to create a second <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ZoomableCanvas</span><span style="color: blue">&gt;</span></span> on top of the first one, but this time I&rsquo;m going to use a bare-bones <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ItemsControl</span><span style="color: blue">&gt;</span></span> instead of a <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;</span></span>.&nbsp; This is because the first <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;</span></span> already gives me scroll bars and keyboard navigation, and I don&rsquo;t need my landmarks to be selectable.&nbsp; I&rsquo;ll place them on top of each other by changing my <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">DockPanel</span><span style="color: blue">&gt;</span></span> into a <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;</span></span> with two rows, and placing both controls in the same row:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;

    &lt;</span><span style="color: #a31515">Grid.RowDefinitions</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">RowDefinition </span><span style="color: red">Height</span><span style="color: blue">="Auto"/&gt;
        &lt;</span><span style="color: #a31515">RowDefinition </span><span style="color: red">Height</span><span style="color: blue">="*"/&gt;
    &lt;/</span><span style="color: #a31515">Grid.RowDefinitions</span><span style="color: blue">&gt;

    &lt;</span><span style="color: #a31515">Slider </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">="MySlider" </span><span style="color: red">Grid.Row</span><span style="color: blue">="0"
            </span><span style="color: red">Maximum</span><span style="color: blue">="1000000" </span><span style="color: red">AutoToolTipPlacement</span><span style="color: blue">="BottomRight"
            </span><span style="color: red">ValueChanged</span><span style="color: blue">="MySlider_ValueChanged"/&gt;

    &lt;</span><span style="color: #a31515">ListBox </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">="MyListBox" </span><span style="color: red">Grid.Row</span><span style="color: blue">="1"&gt;

        . . .
</span><span style="color: blue">
    &lt;/</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;

    &lt;</span><span style="color: #a31515">ItemsControl </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">="MyLandmarks" </span><span style="color: red">Grid.Row</span><span style="color: blue">="1"
                  </span><span style="color: red">VerticalAlignment</span><span style="color: blue">="Top"
                  </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">="Left"
                  </span><span style="color: red">Width</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">ActualWidth</span><span style="color: blue">}"
                  </span><span style="color: red">Height</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">ActualHeight</span><span style="color: blue">}"
                  </span><span style="color: red">Margin</span><span style="color: blue">="2"&gt;

        . . .
</span><span style="color: blue">        
    &lt;/</span><span style="color: #a31515">ItemsControl</span><span style="color: blue">&gt;

&lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;</span></span></pre>
<p>The first thing you might notice is that I&rsquo;m setting <span style="font-family: Consolas, Courier;"><span style="color: red">Width</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">ActualWidth</span><span style="color: blue">}"</span></span> and the same for <span style="font-family: Consolas, Courier;"><span style="color: red">Height</span></span>.&nbsp; But what am I binding to?&nbsp; In the code behind, I&rsquo;ve assigned the <span style="font-family: Consolas, Courier;">DataContext</span> to the first <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> so that I can access it via <span style="font-family: Consolas, Courier;"><span style="color: blue">{</span><span style="color: #a31515">Binding</span><span style="color: blue">}</span></span>s.</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">private void </span>ZoomableCanvas_Loaded(<span style="color: blue">object </span>sender, <span style="color: #2b91af">RoutedEventArgs </span>e)
{
    <span style="color: green">// Store the canvas in a local variable since x:Name doesn't work.
    </span>MyCanvas = (<span style="color: #2b91af">ZoomableCanvas</span>)sender;

    <span style="color: green">// Set the canvas as the DataContext so our overlays can bind to it.
    </span>DataContext = MyCanvas;
}
</span></pre>
<p>My overlay <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ItemsControl</span><span style="color: blue">&gt;</span></span> needs to match the <span style="font-family: Consolas, Courier;"><span style="color: red">Width</span></span> and <span style="font-family: Consolas, Courier;"><span style="color: red">Height</span></span> of the base canvas explicitly because the size keeps changing as the scroll bars appear and disappear.&nbsp; If I didn&rsquo;t make the overlay match then it would draw <em>on top</em> of the scroll bars which would look pretty weird.&nbsp; Another advantage of setting <span style="font-family: Consolas, Courier;">DataContext = MyCanvas</span> is that I can also match the <span style="font-family: Consolas, Courier;"><span style="color: red">Scale</span></span> and <span style="font-family: Consolas, Courier;"><span style="color: red">Offset</span></span> in the same way:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ItemsControl.ItemsPanel</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">ItemsPanelTemplate</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">ZoomableCanvas </span><span style="color: red">Scale</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">Scale</span><span style="color: blue">}"
                        </span><span style="color: red">Offset</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">Offset</span><span style="color: blue">}"
                        </span><span style="color: red">ApplyTransform</span><span style="color: blue">="False"
</span><span style="color: blue">                        </span><span style="color: red">ClipToBounds</span><span style="color: blue">="True"/&gt;
    &lt;/</span><span style="color: #a31515">ItemsPanelTemplate</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">ItemsControl.ItemsPanel</span><span style="color: blue">&gt;</span></span></pre>
<p>The <span style="font-family: Consolas, Courier;"><span style="color: #a31515">ItemContainerStyle</span></span> for our landmarks looks similar to the one for our main items, except this time instead of binding the <span style="font-family: Consolas, Courier;">Width</span> and <span style="font-family: Consolas, Courier;">Height</span> to a factor of the <span style="font-family: Consolas, Courier;">Scale</span>, we&rsquo;ll set the <span style="font-family: Consolas, Courier;">RenderTransform</span> to a <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ScaleTransform</span></span> instead:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ItemsControl.ItemContainerStyle</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">Style </span><span style="color: red">TargetType</span><span style="color: blue">="ContentPresenter"&gt;
        
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="Canvas.Top" </span><span style="color: red">Value</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">top</span><span style="color: blue">}"/&gt;
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="Canvas.Left" </span><span style="color: red">Value</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">left</span><span style="color: blue">}"/&gt;
        
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="RenderTransform"&gt;
            &lt;</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
                &lt;</span><span style="color: #a31515">ScaleTransform </span><span style="color: red">ScaleX</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">ScaleY</span><span style="color: blue">,
                                </span><span style="color: red">RelativeSource</span><span style="color: blue">={</span><span style="color: #a31515">RelativeSource </span><span style="color: red">Self</span><span style="color: blue">}}"&gt;
                    &lt;</span><span style="color: #a31515">ScaleTransform.ScaleY</span><span style="color: blue">&gt;
                        
&lt;</span><span style="color: #a31515">MultiBinding </span><span style="color: red">Converter</span><span style="color: blue">="{</span><span style="color: #a31515">x</span><span style="color: blue">:</span><span style="color: #a31515">Static </span><span style="color: red">ArithmeticConverter</span><span style="color: blue">.Default}"
              </span><span style="color: red">ConverterParameter</span><span style="color: blue">="^"&gt;
    &lt;</span><span style="color: #a31515">Binding </span><span style="color: red">Path</span><span style="color: blue">="Scale"
             </span><span style="color: red">RelativeSource</span><span style="color: blue">="{</span><span style="color: #a31515">RelativeSource
                              </span><span style="color: red">AncestorType</span><span style="color: blue">=ZoomableCanvas}"/&gt;
    &lt;</span><span style="color: #a31515">Binding </span><span style="color: red">Source</span><span style="color: blue">=".333"/&gt;
&lt;/</span><span style="color: #a31515">MultiBinding</span><span style="color: blue">&gt;
                        
                    &lt;/</span><span style="color: #a31515">ScaleTransform.ScaleY</span><span style="color: blue">&gt;
                &lt;/</span><span style="color: #a31515">ScaleTransform</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">Setter</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">Style</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">ItemsControl.ItemContainerStyle</span><span style="color: blue">&gt;</span></span></pre>
<p><span style="font-size: xx-small;">(Sorry about the weird formatting - the blog width is really small.)</span></p>
<p>We&rsquo;re setting the landmark scale to the cube-root of the main scale (<span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Math</span>.Pow(Scale, .333)</span>).&nbsp; We are doing this by passing <span style="font-family: Consolas, Courier;"><span style="color: blue">"^"</span></span> as the <span style="font-family: Consolas, Courier;"><span style="color: red">ConverterParameter</span></span> to our <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2008/06/11/arithmeticconverter.aspx">ArithmeticConverter</a></span></span> as before.&nbsp; This results in the scale of our landmarks changing much slower than the rest of the canvas, so as you zoom out they stay larger longer, and as you zoom in they stay smaller longer.&nbsp; Of course you&rsquo;re welcome to tweak the formula and try completely different equations instead.</p>
<p>For the landmark visual itself, I have a pretty red pushpin that was given to me by <a href="http://blogs.msdn.com/lutzg">Lutz Gerhard</a>.&nbsp; In fact, he was the one who originally told me about &ldquo;power-law scaling&rdquo; in the first place, so a lot of the credit goes to him.</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ItemsControl.ItemTemplate</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">DataTemplate</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">Image </span><span style="color: red">Source</span><span style="color: blue">="Pushpin.png" </span><span style="color: red">Margin</span><span style="color: blue">="-8,-61,0,0"/&gt;
    &lt;/</span><span style="color: #a31515">DataTemplate</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">ItemsControl.ItemTemplate</span><span style="color: blue">&gt;</span></span></pre>
<p>The &ldquo;tip&rdquo; of the pushpin (the point at which it appears to punch through the surface) is about 8 pixels over and 61 pixels down in the image, so I&rsquo;m setting the <span style="font-family: Consolas, Courier;"><span style="color: red">Margin</span></span> to center it on that point.&nbsp; Now I&rsquo;ll simply add a new landmark whenever you double-click:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">protected override void </span>OnMouseDoubleClick(<span style="color: #2b91af">MouseButtonEventArgs </span>e)
{
    <span style="color: blue">var </span>position = MyCanvas.MousePosition;
    MyLandmarks.Items.Add(<span style="color: blue">new </span>{ top = position.Y, left = position.X });
}</span></pre>
<p>And this is what you get!</p>
<p><iframe width="525" src="http://research.microsoft.com/en-us/um/people/kaelr/apps/ZoomableApplication3-2.xbap" height="350"></iframe></p>
<p>You can still use the slider to add and remove items, and double-click to add pushpins.&nbsp; Try adding 1,000,000 items and adding pushpins at each of the 4 corners.&nbsp; Then you can zoom all the way out and get a rough idea of how big a million items really is!&nbsp; You&rsquo;ll also notice that you can double-click when you&rsquo;ve zoomed and panned around, and the pushpin still ends up at the right location.&nbsp; This is because we are using <span style="font-family: Consolas, Courier;">MyCanvas.MousePosition</span> instead of <span style="font-family: Consolas, Courier;">e.GetPosition()</span>.&nbsp; If we were to use the latter, then it would always give us the distance relative to the top-left corner of the control on the screen, so if you double-clicked at the top-left corner of the <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;</span></span> then you&rsquo;d always get a position of (0,0) even if the canvas was scrolled all the way to the bottom-right!&nbsp; <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span>.MousePosition</span> is a handy property that will always give you the coordinates of the mouse pointer <em>in canvas coordinates</em>, so you don&rsquo;t have to do the computation to figure it out yourself.&nbsp;&nbsp; <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> also has <span style="font-family: Consolas, Courier;">GetCanvasPoint(screenPoint)</span> and <span style="font-family: Consolas, Courier;">GetVisualPoint(canvasPoint)</span> if you want to do the same computations but with arbitrary points.</p>
<p>I hope this has given you enough information on how to use the different modes of <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> appropriately.&nbsp; I&rsquo;ve attached the source code for ZoomableApplication3 to this post, so hopefully you&rsquo;ll be up and running with cool effects in no time.&nbsp; And by using the <a href="http://expression.microsoft.com/en-us/ee426922.aspx">Visual State Manager</a> in <a href="http://expression.microsoft.com/en-us/cc136530.aspx">Expression Blend</a> to completely switch the appearance of your items based on the <span style="font-family: Consolas, Courier;">Scale</span>, you&rsquo;ll be well on your way to implementing <a href="http://www.infovis-wiki.net/index.php/Semantic_Zoom">semantic zoom</a>.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/05/17/74/ZoomableApplication3.zip" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-05-17-74/ZoomableApplication3.zip">ZoomableApplication3.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>ZoomableApplication2: A Million Items</title>
      <link>https://docs.microsoft.com/archive/blogs/kaelr/zoomableapplication2-a-million-items</link>
      <pubDate>Wed, 11 Aug 2010 13:24:00 GMT</pubDate>
      <dc:creator><![CDATA[Kael Rowan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaelr/2010/08/11/zoomableapplication2-a-million-items/</guid>
      <description><![CDATA[The original sample for Chris Lovett&rsquo;s VirtualCanvas showed a random set of shapes on a...]]></description>
      <content:encoded><![CDATA[<p>The original sample for Chris Lovett&rsquo;s <a href="http://blogs.msdn.com/b/jgoldb/archive/2008/03/08/performant-virtualized-wpf-canvas.aspx">VirtualCanvas</a> showed a random set of shapes on a canvas.&nbsp; You could use a menu to choose whether to have 5, 500, 12500, or 50000 shapes &ldquo;on the canvas&rdquo;.&nbsp; I use quotation marks because the point of the sample was to show that with UI virtualization you could have 50,000 items in your logical data model while only creating actual <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">UIElement</span></span>s for those that were visible on the screen.&nbsp; That made it possible to scroll back and forth blazingly fast (when zoomed in) since only a couple hundred <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">UIElement</span></span>s were instantiated at any given time.</p>
<p>There are a few things to keep in mind with that original sample.&nbsp; First, in order to get this UI virtualization, your data items were responsible for creating and disposing their own <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">UIElement</span></span>s and visual trees directly from their code-behind, instead of the usual practice of defining <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">DataTemplate</span><span style="color: blue">&gt;</span></span>s somewhere else in XAML.&nbsp; Second, items had to be added to the VirtualCanvas directly, instead of being able to use data-binding with an <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ItemsControl</span></span> like a <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;</span></span>.&nbsp; Third, all data items had to be loaded and remain in RAM even when their respective <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">UIElement</span></span>s are not.&nbsp; 50,000 <span style="font-family: Consolas, Courier;"><span style="color: blue">class</span></span>es or <span style="font-family: Consolas, Courier;"><span style="color: blue">struct</span></span>s by themselves might not be a big deal, but if it takes over a millisecond to load each item then you&rsquo;re talking about a very significant startup time.&nbsp; Fourth, if the user zoomed all the way out then all of the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">UIElement</span></span>s were created at once which would cause the app to hang or simply crash altogether.</p>
<p>For the second post in the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2010/07/29/zoomablecanvas.aspx">ZoomableCanvas</a></span></span> series I&rsquo;m going to recreate the original random shapes sample, but this time I&rsquo;m going to use <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">DataTemplate</span><span style="color: blue">&gt;</span></span>s and a <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;</span></span> so that we get things like selection, scrolling, and keyboard navigation for free.&nbsp; I&rsquo;m also going to show you how UI and data virtualization work, and how you can zoom all the way out and still have a responsive app even with 1,000,000 items.</p>
<p>I&rsquo;m going to start by creating a brand new app called ZoomableApplication2 and adding a reference to the ZoomableCanvas.dll class library that I built for <a href="http://blogs.msdn.com/b/kaelr/archive/2010/08/05/zoomableapplication1-scale-and-offset.aspx">ZoomableApplication1</a>.&nbsp; Then I&rsquo;m going to replace the default <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;</span></span> with a <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;</span></span> and set the <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox.ItemsPanel</span><span style="color: blue">&gt;</span></span> to a <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ZoomableCanvas</span><span style="color: blue">&gt;</span></span>, like this:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Window </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Class</span><span style="color: blue">="ZoomableApplication2.MainWindow"
        </span><span style="color: red">xmlns</span><span style="color: blue">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        </span><span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">x</span><span style="color: blue">="http://schemas.microsoft.com/winfx/2006/xaml"
        </span><span style="color: red">Title</span><span style="color: blue">="MainWindow" </span><span style="color: red">Height</span><span style="color: blue">="350" </span><span style="color: red">Width</span><span style="color: blue">="525"&gt;
    &lt;</span><span style="color: #a31515">ListBox </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">="MyListBox"&gt;
        &lt;</span><span style="color: #a31515">ListBox.ItemsPanel</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">ItemsPanelTemplate</span><span style="color: blue">&gt;
                &lt;</span><span style="color: #a31515">ZoomableCanvas</span><span style="color: blue">/&gt;
            &lt;/</span><span style="color: #a31515">ItemsPanelTemplate</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">ListBox.ItemsPanel</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">Window</span><span style="color: blue">&gt;
</span></span></pre>
<p>Now lets add a bunch of items to the <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;</span></span>.&nbsp; Each of our items will have a top, left, width, and height that places them in a grid-like pattern, kind of like the original VirtualCanvas sample.&nbsp; We&rsquo;ll also give them some random control points for the curves and random colors to make them look pretty.&nbsp; And since we&rsquo;re going to be using <span style="font-family: Consolas, Courier;"><span style="color: blue">{</span><span style="color: #a31515">Binding</span><span style="color: blue">}</span></span>s when we write our XAML, our data items don&rsquo;t even need to be strongly typed. They can just be anonymous bags of properties: </p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">public partial class </span><span style="color: #2b91af">MainWindow </span>: <span style="color: #2b91af">Window
</span>{
    <span style="color: blue">public </span>MainWindow()
    {
        InitializeComponent();

        DataItems = <span style="color: blue">new </span><span style="color: #2b91af">ObservableCollection</span>&lt;<span style="color: blue">object</span>&gt;();
        MyListBox.ItemsSource = DataItems;

        PopulateDataItems(100);
    }

    <span style="color: blue">private </span><span style="color: #2b91af">ObservableCollection</span>&lt;<span style="color: blue">object</span>&gt; DataItems;

    <span style="color: blue">private void </span>PopulateDataItems(<span style="color: blue">int </span>newCount)
    {
        <span style="color: green">// Remove items if our new count is less than our current count.
        </span><span style="color: blue">while </span>(newCount &lt; DataItems.Count)
        {
            DataItems.RemoveAt(DataItems.Count - 1);
        }
        <span style="color: green">// Add items if our new count is more than our current count.
        </span><span style="color: blue">while </span>(newCount &gt; DataItems.Count)
        {
            <span style="color: green">// Give each item a deterministic seed.
            </span><span style="color: blue">var </span>i = DataItems.Count;
            <span style="color: blue">var </span>rand = <span style="color: blue">new </span><span style="color: #2b91af">Random</span>(i);
            <span style="color: blue">var </span>sqrt = (<span style="color: blue">int</span>)<span style="color: #2b91af">Math</span>.Sqrt(i);

            <span style="color: green">// With a random width and height between 50 and 100.
            </span><span style="color: blue">var </span>width = rand.Next(50, 100);
            <span style="color: blue">var </span>height = rand.Next(50, 100);

            <span style="color: green">// And place it at a random position in a grid-like pattern.
            </span><span style="color: blue">var </span>top = <span style="color: #2b91af">Math</span>.Min(sqrt, i - <span style="color: #2b91af">Math</span>.Pow(sqrt, 2))
                      * 100 + rand.Next(100 - height);
            <span style="color: blue">var </span>left = <span style="color: #2b91af">Math</span>.Min(sqrt, sqrt * 2 - (i - <span style="color: #2b91af">Math</span>.Pow(sqrt, 2)))
                       * 100 + rand.Next(100 - width);

            <span style="color: green">// Randomly generate the outline of the item.
            </span><span style="color: blue">var </span>type = rand.Next(3);
            <span style="color: blue">var </span>data = type == 0 ? <span style="color: #a31515">"ellipse" </span>:
                       type == 1 ? <span style="color: #a31515">"rectangle" </span>:
                       <span style="color: #2b91af">String</span>.Format(<span style="color: #a31515">"M{0},{1} C{2},{3} {4},{5} {6},{7}"</span>,
                           rand.NextDouble(),
                           rand.NextDouble(),
                           rand.NextDouble(),
                           rand.NextDouble(),
                           rand.NextDouble(),
                           rand.NextDouble(),
                           rand.NextDouble(),
                           rand.NextDouble());

            <span style="color: green">// Give it random gradient colors.
            </span><span style="color: blue">var </span>brush = <span style="color: blue">new </span><span style="color: #2b91af">LinearGradientBrush</span>(
                            <span style="color: #2b91af">Color</span>.FromScRgb(1f, (<span style="color: blue">float</span>)rand.NextDouble(),
                                                (<span style="color: blue">float</span>)rand.NextDouble(), 
                                                (<span style="color: blue">float</span>)rand.NextDouble()),
                            <span style="color: #2b91af">Color</span>.FromScRgb(1f, (<span style="color: blue">float</span>)rand.NextDouble(),
                                                (<span style="color: blue">float</span>)rand.NextDouble(),
                                                (<span style="color: blue">float</span>)rand.NextDouble()),
                            180 * rand.NextDouble());

            <span style="color: green">// Add it to the pool of data items.
            </span>DataItems.Add(<span style="color: blue">new </span>{ top, left, width, height, data, brush, i });
        }
    }
}
</span></pre>
<p>Now lets define the <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Style</span><span style="color: blue">&gt;</span></span> for our <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ListBoxItem</span></span>s and the <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">DataTemplate</span><span style="color: blue">&gt;</span></span>s for the three different data &ldquo;types&rdquo;.&nbsp; The first part of the <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Style</span><span style="color: blue">&gt;</span></span> will be hooking up the <span style="font-family: Consolas, Courier;"><span style="color: blue">Canvas.Top</span></span>, <span style="font-family: Consolas, Courier;"><span style="color: blue">Canvas.Left</span></span>, <span style="font-family: Consolas, Courier;"><span style="color: blue">Width</span></span>, and <span style="font-family: Consolas, Courier;"><span style="color: blue">Height</span></span> properties for each item, as well as setting the content alignment to <span style="font-family: Consolas, Courier;"><span style="color: blue">Stretch</span></span> (since by default <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ListBoxItem</span></span>s left-justify their content).&nbsp; I&rsquo;ll also give each <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ListBoxItem</span></span> some <span style="font-family: Consolas, Courier;"><span style="color: blue">Padding</span></span> so that the blue selection highlight is clearly visible around an item when it&rsquo;s selected.&nbsp; The second part of the <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Style</span><span style="color: blue">&gt;</span></span> will be defining our <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">DataTemplate</span><span style="color: blue">&gt;</span></span>s based on the value of the <span style="font-family: Consolas, Courier;">data</span> property.&nbsp; Since in this case our data already represents simple shapes, our templates are going to be pretty straightforward:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox.ItemContainerStyle</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">Style </span><span style="color: red">TargetType</span><span style="color: blue">="ListBoxItem"&gt;

        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="Canvas.Top" </span><span style="color: red">Value</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">top</span><span style="color: blue">}"/&gt;
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="Canvas.Left" </span><span style="color: red">Value</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">left</span><span style="color: blue">}"/&gt;
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="Width" </span><span style="color: red">Value</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">width</span><span style="color: blue">}"/&gt;
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="Height" </span><span style="color: red">Value</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">height</span><span style="color: blue">}"/&gt;
        
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="VerticalContentAlignment" </span><span style="color: red">Value</span><span style="color: blue">="Stretch"/&gt;
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="HorizontalContentAlignment" </span><span style="color: red">Value</span><span style="color: blue">="Stretch"/&gt;
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="Padding" </span><span style="color: red">Value</span><span style="color: blue">="5"/&gt;
        
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="ContentTemplate"&gt;
            &lt;</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
                &lt;</span><span style="color: #a31515">DataTemplate</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
                        &lt;</span><span style="color: #a31515">Path </span><span style="color: red">Data</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">data</span><span style="color: blue">}"
                              </span><span style="color: red">Stroke</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">brush</span><span style="color: blue">}"
                              </span><span style="color: red">StrokeThickness</span><span style="color: blue">="2"
                              </span><span style="color: red">Stretch</span><span style="color: blue">="Fill"/&gt;
                        &lt;</span><span style="color: #a31515">TextBlock </span><span style="color: red">Text</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">i</span><span style="color: blue">}"
                                   </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">="Center"
                                   </span><span style="color: red">VerticalAlignment</span><span style="color: blue">="Center"/&gt;
                    &lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
                &lt;/</span><span style="color: #a31515">DataTemplate</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">Setter</span><span style="color: blue">&gt;
        
        &lt;</span><span style="color: #a31515">Style.Triggers</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">DataTrigger </span><span style="color: red">Binding</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">data</span><span style="color: blue">}" </span><span style="color: red">Value</span><span style="color: blue">="rectangle"&gt;
                &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="ContentTemplate"&gt;
                    &lt;</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
                        &lt;</span><span style="color: #a31515">DataTemplate</span><span style="color: blue">&gt;
                            &lt;</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
                                &lt;</span><span style="color: #a31515">Rectangle </span><span style="color: red">Fill</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">brush</span><span style="color: blue">}"
                                           </span><span style="color: red">RadiusX</span><span style="color: blue">="10"
                                           </span><span style="color: red">RadiusY</span><span style="color: blue">="10"/&gt;
                                &lt;</span><span style="color: #a31515">TextBlock </span><span style="color: red">Text</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">i</span><span style="color: blue">}"
                                           </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">="Center"
                                           </span><span style="color: red">VerticalAlignment</span><span style="color: blue">="Center"/&gt;
                            &lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
                        &lt;/</span><span style="color: #a31515">DataTemplate</span><span style="color: blue">&gt;
                    &lt;/</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
                &lt;/</span><span style="color: #a31515">Setter</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">DataTrigger</span><span style="color: blue">&gt;

            &lt;</span><span style="color: #a31515">DataTrigger </span><span style="color: red">Binding</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">data</span><span style="color: blue">}" </span><span style="color: red">Value</span><span style="color: blue">="ellipse"&gt;
                &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="ContentTemplate"&gt;
                    &lt;</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
                        &lt;</span><span style="color: #a31515">DataTemplate</span><span style="color: blue">&gt;
                            &lt;</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
                                &lt;</span><span style="color: #a31515">Ellipse </span><span style="color: red">Fill</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">brush</span><span style="color: blue">}"/&gt;
                                &lt;</span><span style="color: #a31515">TextBlock </span><span style="color: red">Text</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">i</span><span style="color: blue">}"
                                           </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">="Center"
                                           </span><span style="color: red">VerticalAlignment</span><span style="color: blue">="Center"/&gt;
                            &lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
                        &lt;/</span><span style="color: #a31515">DataTemplate</span><span style="color: blue">&gt;
                    &lt;/</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
                &lt;/</span><span style="color: #a31515">Setter</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">DataTrigger</span><span style="color: blue">&gt;
            
        &lt;/</span><span style="color: #a31515">Style.Triggers</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">Style</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">ListBox.ItemContainerStyle</span><span style="color: blue">&gt;</span></span></pre>
<p>And if you run the app with just the code I&rsquo;ve shown you so far, you already get a pretty cool little canvas application showing 100 random shapes with selection, scroll bars, and keyboard navigation:</p>
<p><iframe width="525" src="http://research.microsoft.com/en-us/um/people/kaelr/apps/ZoomableApplication2-1.xbap" height="350"></iframe><br /><span style="font-size: xx-small;">(I&rsquo;ve embedded the sample as an XBAP in an <span style="font-family: Consolas, Courier;">&lt;iframe&gt;</span> above this line, so you should see a live sample and be able to interact with it if you&rsquo;re using Internet Explorer and have .NET 4.0 installed.)</span></p>
<p>You may have noticed that if you select an item with the mouse and keep holding down the mouse button while moving the mouse off the canvas, it will start to pan automatically, even though we haven&rsquo;t hooked up any zooming or panning code yet!&nbsp; It&rsquo;s actually the <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;</span></span> that&rsquo;s doing this, since it knows how to talk to the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">IScrollInfo</span></span> interface that the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> implements internally.&nbsp; When you are selecting items by holding the mouse and dragging, the <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;</span></span> automatically tells the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> to scroll to the next item.&nbsp; <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> then does this by setting its <span style="font-family: Consolas, Courier;">Offset</span> property accordingly, which results in the automatic &ldquo;pan&rdquo;.</p>
<p>Unfortunately the built-in <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;</span></span> &ldquo;panning&rdquo; is a little clunky, since it does it on an item-by-item basis instead of a pixel-by-pixel basis.&nbsp; You can of course use the scroll bars instead, but that&rsquo;s not as cool as dragging the canvas to pan, and there&rsquo;s no way to zoom.&nbsp; So lets hook up our own mouse handlers just like we did in <a href="http://blogs.msdn.com/b/kaelr/archive/2010/08/05/zoomableapplication1-scale-and-offset.aspx">ZoomableApplication1</a>, but this time we&rsquo;ll get even fancier by zooming in and out &ldquo;around the mouse&rdquo; instead of the top-left.</p>
<p>If you remember from <a href="http://blogs.msdn.com/b/kaelr/archive/2010/08/05/zoomableapplication1-scale-and-offset.aspx">ZoomableApplication1</a>, we were able to set the <span style="font-family: Consolas, Courier;">Scale</span> and <span style="font-family: Consolas, Courier;">Offset</span> of the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> by setting its <span style="font-family: Consolas, Courier;"><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">="MyCanvas"</span></span> in the XAML.&nbsp; Unfortunately this feature doesn&rsquo;t work in WPF when dealing with <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ItemsPanelTemplate</span><span style="color: blue">&gt;</span></span>s, and the <span style="font-family: Consolas, Courier;">ItemsHost</span> property on <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ListBox</span></span> is <span style="font-family: Consolas, Courier;"><span style="color: blue">internal</span></span>.&nbsp; So we&rsquo;ll either have to search down the visual tree to find the canvas, or simply assign it to a local variable when it&rsquo;s created.&nbsp; I think the latter is cleaner, so lets add a <span style="font-family: Consolas, Courier;">ZoomableCanvas_Loaded</span> handler and capture it at that point.&nbsp; And while we&rsquo;re capturing things, lets capture the mouse this time too:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox.ItemsPanel</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">ItemsPanelTemplate</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">ZoomableCanvas </span><span style="color: red">Loaded</span><span style="color: blue">="ZoomableCanvas_Loaded"/&gt;
    &lt;/</span><span style="color: #a31515">ItemsPanelTemplate</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">ListBox.ItemsPanel</span><span style="color: blue">&gt;</span></span></pre>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas </span>MyCanvas;
<span style="color: #2b91af">Point </span>LastMousePosition;

<span style="color: blue">private void </span>ZoomableCanvas_Loaded(<span style="color: blue">object </span>sender, <span style="color: #2b91af">RoutedEventArgs </span>e)
{
    <span style="color: green">// Store the canvas in a local variable since x:Name doesn't work.
    </span>MyCanvas = (<span style="color: #2b91af">ZoomableCanvas</span>)sender;
}

<span style="color: blue">protected override void </span>OnPreviewMouseMove(<span style="color: #2b91af">MouseEventArgs </span>e)
{
    <span style="color: blue">var </span>position = e.GetPosition(MyListBox);
    <span style="color: blue">if </span>(e.LeftButton == <span style="color: #2b91af">MouseButtonState</span>.Pressed
        &amp;&amp; !(e.OriginalSource <span style="color: blue">is </span><span style="color: #2b91af">Thumb</span>)) <span style="color: green">// Don't block the scrollbars.
    </span>{
        CaptureMouse();
        MyCanvas.Offset -= position - LastMousePosition;
        e.Handled = <span style="color: blue">true</span>;
    }
    <span style="color: blue">else
    </span>{
        ReleaseMouseCapture();
    }
    LastMousePosition = position;
}

<span style="color: blue">protected override void </span>OnPreviewMouseWheel(<span style="color: #2b91af">MouseWheelEventArgs </span>e)
{
    <span style="color: blue">var </span>x = <span style="color: #2b91af">Math</span>.Pow(2, e.Delta / 3.0 / <span style="color: #2b91af">Mouse</span>.MouseWheelDeltaForOneLine);
    MyCanvas.Scale *= x;

    <span style="color: green">// Adjust the offset to make the point under the mouse stay still.
    </span><span style="color: blue">var </span>position = (<span style="color: #2b91af">Vector</span>)e.GetPosition(MyListBox);
    MyCanvas.Offset = (<span style="color: #2b91af">Point</span>)((<span style="color: #2b91af">Vector</span>)
        (MyCanvas.Offset + position) * x - position);

    e.Handled = <span style="color: blue">true</span>;
}
</span></pre>
<p>Before I embed another sample, let&rsquo;s do one more thing.&nbsp; Instead of having a fixed set of 100 shapes, let&rsquo;s dock a <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Slider</span><span style="color: blue">&gt;</span></span> to the top that lets us increase and decrease the number of shapes at will.&nbsp; We&rsquo;ll remove the call to <span style="font-family: Consolas, Courier;">PopulateDataItems(100)</span> that we initially had above, and we&rsquo;ll call it from the <span style="font-family: Consolas, Courier;">MySlider_ValueChanged</span> instead:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">DockPanel</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">Slider </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">="MySlider" </span><span style="color: red">DockPanel.Dock</span><span style="color: blue">="Top"
            </span><span style="color: red">Maximum</span><span style="color: blue">="10000" </span><span style="color: red">AutoToolTipPlacement</span><span style="color: blue">="BottomRight"
            </span><span style="color: red">ValueChanged</span><span style="color: blue">="MySlider_ValueChanged"/&gt;

    &lt;</span><span style="color: #a31515">ListBox </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">="MyListBox"&gt;

        . . .

    &lt;/</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">DockPanel</span><span style="color: blue">&gt;</span></span></pre>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">private void </span>MySlider_ValueChanged(<span style="color: blue">object </span>sender, <span style="color: #2b91af">EventArgs </span>e)
{
    PopulateDataItems((<span style="color: blue">int</span>)MySlider.Value);
}
</span></pre>
<p><iframe width="525" src="http://research.microsoft.com/en-us/um/people/kaelr/apps/ZoomableApplication2-2.xbap" height="350"></iframe></p>
<p>The thing to notice here (other than the fun panning and zooming) is that no matter how many shapes you create, you can scroll back and forth extremely smoothly as long as your are zoomed in enough so that only a few hundred shapes are on your screen at a time.&nbsp; This is because of the built-in UI virtualization in <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span>.&nbsp;&nbsp; </p>
<p>It&rsquo;s nice that we get virtualization for free without doing any extra work, but you probably noticed it took a <em>really long time</em> to get that slider all the way over to the right.&nbsp; This is because the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> had to create and measure each of those shapes (albeit just once) in order to determine where they would end up on the canvas.&nbsp; We can skip this step by having our <span style="font-family: Consolas, Courier;">ItemsSource</span> implement <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span>.<span style="color: #2b91af">ISpatialItemsSource</span></span>.&nbsp; This will cause the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> to ask our <span style="font-family: Consolas, Courier;">ItemsSource</span> which items are in view instead of the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> keeping track of them internally, which means the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> doesn&rsquo;t need to know where all the shapes are up front.&nbsp; It&rsquo;s pretty easy to implement <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ISpatialItemsSource</span></span>; you just need to know how to figure out the index of the items that intersect a given <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Rect</span></span>, and you need to know the overall bounding box (extent) of all the items in your set.&nbsp; Since all of our items are in a grid-like pattern, it&rsquo;s very quick to determine both of these things.&nbsp; I&rsquo;m just going to create a new class that derives from <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ObservableCollection</span>&lt;<span style="color: blue">object</span>&gt;</span> (since that&rsquo;s what we were using before), and implement <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ISpatialItemsSource</span></span> by using some grid-like math:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">public class </span><span style="color: #2b91af">GridLikeItemsSource </span>: 
    <span style="color: #2b91af">ObservableCollection</span>&lt;<span style="color: blue">object</span>&gt;,
    <span style="color: #2b91af">ZoomableCanvas</span>.<span style="color: #2b91af">ISpatialItemsSource
</span>{
    <span style="color: blue">public </span><span style="color: #2b91af">Rect </span>Extent
    {
        <span style="color: blue">get
        </span>{
            <span style="color: blue">var </span>sqrt = <span style="color: #2b91af">Math</span>.Sqrt(Count);
            <span style="color: blue">return new </span><span style="color: #2b91af">Rect</span>(0, 0, 
                100 * (<span style="color: #2b91af">Math</span>.Ceiling(sqrt)), 
                100 * (<span style="color: #2b91af">Math</span>.Round(sqrt)));
        }
    }

    <span style="color: blue">public </span><span style="color: #2b91af">IEnumerable</span>&lt;<span style="color: blue">int</span>&gt; Query(<span style="color: #2b91af">Rect </span>rectangle)
    {
        rectangle.Intersect(Extent);

        <span style="color: blue">var </span>top = <span style="color: #2b91af">Math</span>.Floor(rectangle.Top / 100);
        <span style="color: blue">var </span>left = <span style="color: #2b91af">Math</span>.Floor(rectangle.Left / 100);
        <span style="color: blue">var </span>right = <span style="color: #2b91af">Math</span>.Ceiling(rectangle.Right / 100);
        <span style="color: blue">var </span>bottom = <span style="color: #2b91af">Math</span>.Ceiling(rectangle.Bottom / 100);

        <span style="color: blue">for </span>(<span style="color: blue">var </span>x = <span style="color: #2b91af">Math</span>.Max(left, 0); x &lt;= right; x++)
        {
            <span style="color: blue">for </span>(<span style="color: blue">var </span>y = <span style="color: #2b91af">Math</span>.Max(top, 0); y &lt;= bottom; y++)
            {
                <span style="color: blue">var </span>i = x &gt; y ?
                    <span style="color: #2b91af">Math</span>.Pow(x, 2) + y :
                    <span style="color: #2b91af">Math</span>.Pow(y, 2) + 2 * y - x;
                <span style="color: blue">if </span>(i &lt; Count)
                {
                    <span style="color: blue">yield return </span>(<span style="color: blue">int</span>)i;
                }
            }
        }
    }

    <span style="color: blue">public event </span><span style="color: #2b91af">EventHandler </span>ExtentChanged;

    <span style="color: blue">public event </span><span style="color: #2b91af">EventHandler </span>QueryInvalidated;
}
</span></pre>
<p>I&rsquo;ll also change the corresponding type in <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">MainWindow</span></span>, but I&rsquo;ll leave everything else the same.</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">public </span>MainWindow()
{
    InitializeComponent();

    DataItems = <span style="color: blue">new </span><span style="color: #2b91af">GridLikeItemsSource</span>();
    MyListBox.ItemsSource = DataItems;
}

<span style="color: blue">private </span><span style="color: #2b91af">GridLikeItemsSource </span>DataItems;
</span></pre>
<p>Here is the sample again, but you should be able to feel a big difference when sliding the slider across:</p>
<p><iframe width="525" src="http://research.microsoft.com/en-us/um/people/kaelr/apps/ZoomableApplication2-3.xbap" height="350"></iframe></p>
<p>Moving the slider all the way to the right is still not <em>instantaneous</em>, but that&rsquo;s because it still takes a little bit of time to create each data item and add it to the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ObservableCollection</span></span>.&nbsp; It&rsquo;s also not <em>free</em> since each item takes a little bit of RAM as well.&nbsp; This is fine for 10,000 items, but what about 100,000?&nbsp; Or a million?&nbsp; Or a billion?&nbsp; What if I wanted to show a node-link diagram for every web page on the internet?&nbsp; There&rsquo;s over 150 billion web pages according to <a href="http://www.archive.org">www.archive.org</a>, and who knows how many links!&nbsp; You wouldn&rsquo;t even be able to fit all of that data into RAM!</p>
<p>With data virtualization, you can have a canvas with as many items as you want.&nbsp; Well, ok, that&rsquo;s not <em>entirely </em>true.&nbsp; You can actually only have up to 2,147,483,647 items <em>per canvas</em>, because that&rsquo;s the upper limit of the <span style="font-family: Consolas, Courier;"><span style="color: blue">int</span></span> indexer on <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">IList</span></span>.&nbsp; The key to data virtualization is that when you implement <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ISpatialItemsSource</span></span>, your list is never actually enumerated.&nbsp; The only thing that is called is <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ISpatialItemsSource</span>.Query</span> (and <span style="font-family: Consolas, Courier;">Extent</span>), so your list is only asked for the items that are actually on the screen.&nbsp; So instead of deriving from <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ObservableCollection</span></span> and adding items to it when the slider value changes, let&rsquo;s implement a custom <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">IList</span></span> that fetches items on-demand.</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">public class </span><span style="color: #2b91af">GridLikeItemsSource </span>: 
    <span style="color: #2b91af">IList</span>,
    <span style="color: #2b91af">ZoomableCanvas</span>.<span style="color: #2b91af">ISpatialItemsSource
</span>{
    <span style="color: blue">public </span><span style="color: #2b91af">Rect </span>Extent
    {
        . . . (same code as above) . . .
    }

    <span style="color: blue">public </span><span style="color: #2b91af">IEnumerable</span>&lt;<span style="color: blue">int</span>&gt; Query(<span style="color: #2b91af">Rect </span>rectangle)
    {
        . . . (same code as above) . . .
    }

    <span style="color: blue">public event </span><span style="color: #2b91af">EventHandler </span>ExtentChanged;

    <span style="color: blue">public event </span><span style="color: #2b91af">EventHandler </span>QueryInvalidated;

    <span style="color: blue">private int </span>count;
    
    <span style="color: blue">public int </span>Count
    {
        <span style="color: blue">get
        </span>{
            <span style="color: blue">return </span>count;
        }
        <span style="color: blue">set
        </span>{
            count = <span style="color: blue">value</span>;
            ExtentChanged(<span style="color: blue">this</span>, <span style="color: #2b91af">EventArgs</span>.Empty);
            QueryInvalidated(<span style="color: blue">this</span>, <span style="color: #2b91af">EventArgs</span>.Empty);
        }
    }

    <span style="color: blue">public object this</span>[<span style="color: blue">int </span>i]
    {
        <span style="color: blue">get
        </span>{
            <span style="color: green">// Give the item a deterministic seed.
            </span><span style="color: blue">var </span>rand = <span style="color: blue">new </span><span style="color: #2b91af">Random</span>(i);
            <span style="color: blue">var </span>sqrt = (<span style="color: blue">int</span>)<span style="color: #2b91af">Math</span>.Sqrt(i);

            <span style="color: green">// With a random width and height between 50 and 100.</span>

            . . . (same code as PopulateDataItems above) . . .

            <span style="color: blue">return new </span>{ top, left, width, height, data, brush, i };
        }
        <span style="color: blue">set
        </span>{
        }
    }

    <span style="color: blue">#region </span>Irrelevant IList Members . . .
}
</span></pre>
<p>Notice that this time I&rsquo;m actually raising the <span style="font-family: Consolas, Courier;">ExtentChanged</span> and <span style="font-family: Consolas, Courier;">QueryInvalidated</span> events.&nbsp; This wasn&rsquo;t necessary before because <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ObservableCollection</span></span> already raises enough events to broadcast to the world that everything has changed.&nbsp; But now that we&rsquo;re trimmed down, we raise <span style="font-family: Consolas, Courier;">ExtentChanged</span> to let the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> know to update its scrollbar information, and we raise <span style="font-family: Consolas, Courier;">QueryInvalidated</span> to let the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> know to call <span style="font-family: Consolas, Courier;">Query</span> again.&nbsp; If we wanted to be <em>totally </em>optimized then we would only call <span style="font-family: Consolas, Courier;">QueryInvalidated</span> when we know that another call to <span style="font-family: Consolas, Courier;">Query</span> with the same <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Rect</span></span> would give <em>different</em> results.&nbsp; But our <span style="font-family: Consolas, Courier;">Query</span> method runs practically instantaneously so it doesn&rsquo;t really matter if it&rsquo;s called tons of times.</p>
<p>Now lets update our <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Slider</span><span style="color: blue">&gt;</span></span> to have <strong>a million items</strong> and replace the <span style="font-family: Consolas, Courier;">PopulateDataItems</span> code with a simple setter to <span style="font-family: Consolas, Courier;">DataItems.Count</span>:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Slider </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">="MySlider" </span><span style="color: red">DockPanel.Dock</span><span style="color: blue">="Top"
        </span><span style="color: red">Maximum</span><span style="color: blue">="1000000" </span><span style="color: red">AutoToolTipPlacement</span><span style="color: blue">="BottomRight"
        </span><span style="color: red">ValueChanged</span><span style="color: blue">="MySlider_ValueChanged"/&gt;
</span></span></pre>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">private void </span>MySlider_ValueChanged(<span style="color: blue">object </span>sender, <span style="color: #2b91af">EventArgs </span>e)
{
    DataItems.Count = (<span style="color: blue">int</span>)MySlider.Value;
}
</span></pre>
<p>One more thing before we run the app.&nbsp; I know that you&rsquo;re going to slide the slider all the way to the right (which will be instantaneous with our data-virtualized <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">IList</span></span>), but then the first thing you&rsquo;re going to do after that is zoom out!&nbsp; But we haven&rsquo;t done anything to prevent WPF from trying to show all 1,000,000 shapes, so the app will hang and/or crash just like every other VirtualCanvas sample out there, and my blog will probably crash and burn right along with it.&nbsp; So before I let you unleash your mouse wheel on the next sample, I&rsquo;m going to put in some safeguards.</p>
<p>WPF can only handle between about 1,000 to 10,000 primitives on the screen while still remaining responsive, depending on your CPU and graphics card.&nbsp; 10,000 primitives isn&rsquo;t a lot when you realize that even our simple shapes use 5 primitives each (you can use <a href="http://snoopwpf.codeplex.com/">Snoop</a> to see why).&nbsp; <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> doesn&rsquo;t have any magic to get around that, but it does have convenient ways to limit the number of elements on the screen, and ways to control the time it takes to create them.&nbsp; The first property, <span style="font-family: Consolas, Courier;">RealizationLimit</span>, is the maximum number of elements that <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> will try to maintain on the screen at any given time.&nbsp; The second property, <span style="font-family: Consolas, Courier;">RealizationRate</span>, is the number of elements that <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> will create and/or dispose in a single &ldquo;batch&rdquo;.&nbsp; This is really only useful when you combine it with the third property, <span style="font-family: Consolas, Courier;">RealizationPriority</span>, which controls when these batches take place.&nbsp; By default the <span style="font-family: Consolas, Courier;">RealizationPriority</span> is <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">DispatcherPriority</span>.Normal</span>, which basically means it performs the batches right away even if it means hanging the UI.</p>
<p>For our particular sample, I&rsquo;m going to set <span style="font-family: Consolas, Courier;">RealizationLimit</span> to 1000, <span style="font-family: Consolas, Courier;">RealizationRate</span> to 10, and <span style="font-family: Consolas, Courier;">RealizationPriority</span> to <span style="font-family: Consolas, Courier;">Background</span>.&nbsp; This means that the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> will try to have a maximum of 1000 elements on the screen at a time (5,000 primitives in our case), it will create and dispose 10 of them at a time until it gets to that number, and it will process input events like the mouse and keyboard before each batch.&nbsp; This will let the app remain responsive and allow you to pan and zoom way out, with the tradeoff being that you&rsquo;ll see a bit of a &ldquo;flicker&rdquo; while the shapes are being created and disposed and you&rsquo;ll see big gaps between the 1,000 items on the screen.</p>
<p>Here is the code:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox.ItemsPanel</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">ItemsPanelTemplate</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">ZoomableCanvas </span><span style="color: red">Loaded</span><span style="color: blue">="ZoomableCanvas_Loaded"
                        </span><span style="color: red">RealizationLimit</span><span style="color: blue">="1000"
                        </span><span style="color: red">RealizationRate</span><span style="color: blue">="10"
                        </span><span style="color: red">RealizationPriority</span><span style="color: blue">="Background"/&gt;
    &lt;/</span><span style="color: #a31515">ItemsPanelTemplate</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">ListBox.ItemsPanel</span><span style="color: blue">&gt;
</span></span></pre>
<p>And finally, here is the app!</p>
<p><iframe width="525" src="http://research.microsoft.com/en-us/um/people/kaelr/apps/ZoomableApplication2-4.xbap" height="350"></iframe></p>
<p>The distribution of elements on the canvas when there is a <span style="font-family: Consolas, Courier;">RealizationLimit</span> is not random.&nbsp; When you&rsquo;re not implementing <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ISpatialItemsSource</span></span> yourself, the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> will by default show larger items (width + height) before showing smaller ones.&nbsp; In other words, if your <span style="font-family: Consolas, Courier;">RealizationLimit</span> is 1000, the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> will create elements for the 1000 biggest items (within the viewbox) first, and then it will dispose the rest.&nbsp; But if you <em>are</em> implementing <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ISpatialItemsSource</span></span> yourself, then <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> will create elements for the <em>first</em> 1000 items that you return from the <span style="font-family: Consolas, Courier;">Query</span> method, in the order you return them, so it&rsquo;s up to you to prioritize which ones show up on the canvas first.&nbsp; You&rsquo;re welcome to use <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2009/05/21/priorityquadtree.aspx">PriorityQuadTree</a></span></span> if you&rsquo;d like, but for this particular sample I was able to come up with a more efficient technique to prioritize evenly-distributed items since the elements are in a grid-like pattern:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">public </span><span style="color: #2b91af">IEnumerable</span>&lt;<span style="color: blue">int</span>&gt; Query(<span style="color: #2b91af">Rect </span>rectangle)
{
    rectangle.Intersect(Extent);

    <span style="color: blue">var </span>top = <span style="color: #2b91af">Math</span>.Floor(rectangle.Top / 100);
    <span style="color: blue">var </span>left = <span style="color: #2b91af">Math</span>.Floor(rectangle.Left / 100);
    <span style="color: blue">var </span>right = <span style="color: #2b91af">Math</span>.Ceiling(rectangle.Right / 100);
    <span style="color: blue">var </span>bottom = <span style="color: #2b91af">Math</span>.Ceiling(rectangle.Bottom / 100);
    <span style="color: blue">var </span>width = <span style="color: #2b91af">Math</span>.Max(right - left, 0);
    <span style="color: blue">var </span>height = <span style="color: #2b91af">Math</span>.Max(bottom - top, 0);

    <span style="color: blue">foreach </span>(<span style="color: blue">var </span>cell <span style="color: blue">in </span>Quadivide(<span style="color: blue">new </span><span style="color: #2b91af">Rect</span>(left, top, width, height)))
    {
        <span style="color: blue">var </span>x = cell.X;
        <span style="color: blue">var </span>y = cell.Y;
        <span style="color: blue">var </span>i = x &gt; y ?
            <span style="color: #2b91af">Math</span>.Pow(x, 2) + y :
            <span style="color: #2b91af">Math</span>.Pow(y, 2) + 2 * y - x;
        <span style="color: blue">if </span>(i &lt; Count)
        {
            <span style="color: blue">yield return </span>(<span style="color: blue">int</span>)i;
        }
    }
}

<span style="color: blue">private </span><span style="color: #2b91af">IEnumerable</span>&lt;<span style="color: #2b91af">Point</span>&gt; Quadivide(<span style="color: #2b91af">Rect </span>area)
{
    <span style="color: blue">if </span>(area.Width &gt; 0 &amp;&amp; area.Height &gt; 0)
    {
        <span style="color: blue">var </span>center = area.GetCenter();
        <span style="color: blue">var </span>x = <span style="color: #2b91af">Math</span>.Floor(center.X);
        <span style="color: blue">var </span>y = <span style="color: #2b91af">Math</span>.Floor(center.Y);
        <span style="color: blue">yield return new </span><span style="color: #2b91af">Point</span>(x, y);

        <span style="color: blue">var </span>quad1 = <span style="color: blue">new </span><span style="color: #2b91af">Rect</span>(area.TopLeft, <span style="color: blue">new </span><span style="color: #2b91af">Point</span>(x, y + 1));
        <span style="color: blue">var </span>quad2 = <span style="color: blue">new </span><span style="color: #2b91af">Rect</span>(area.TopRight, <span style="color: blue">new </span><span style="color: #2b91af">Point</span>(x, y));
        <span style="color: blue">var </span>quad3 = <span style="color: blue">new </span><span style="color: #2b91af">Rect</span>(area.BottomLeft, <span style="color: blue">new </span><span style="color: #2b91af">Point</span>(x + 1, y + 1));
        <span style="color: blue">var </span>quad4 = <span style="color: blue">new </span><span style="color: #2b91af">Rect</span>(area.BottomRight, <span style="color: blue">new </span><span style="color: #2b91af">Point</span>(x + 1, y));

        <span style="color: blue">var </span>quads = <span style="color: blue">new </span><span style="color: #2b91af">Queue</span>&lt;<span style="color: #2b91af">IEnumerator</span>&lt;<span style="color: #2b91af">Point</span>&gt;&gt;();
        quads.Enqueue(Quadivide(quad1).GetEnumerator());
        quads.Enqueue(Quadivide(quad2).GetEnumerator());
        quads.Enqueue(Quadivide(quad3).GetEnumerator());
        quads.Enqueue(Quadivide(quad4).GetEnumerator());
        <span style="color: blue">while </span>(quads.Count &gt; 0)
        {
            <span style="color: blue">var </span>quad = quads.Dequeue();
            <span style="color: blue">if </span>(quad.MoveNext())
            {
                <span style="color: blue">yield return </span>quad.Current;
                quads.Enqueue(quad);
            }
        }
    }
}
</span></pre>
<p>So there you have it!&nbsp; Hopefully this (rather long) blog post gave you a good idea of how use the built-in UI virtualization, how to implement your own data data virtualization, and how to put on limits to keep your app responsive as a last resort.&nbsp; I&rsquo;ve attached the final ZoomableApplication2 project to this post.&nbsp; Phew!</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/04/90/70/ZoomableApplication2.zip" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-04-90-70/ZoomableApplication2.zip">ZoomableApplication2.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>ZoomableApplication1: Scale and Offset</title>
      <link>https://docs.microsoft.com/archive/blogs/kaelr/zoomableapplication1-scale-and-offset</link>
      <pubDate>Thu, 05 Aug 2010 20:44:00 GMT</pubDate>
      <dc:creator><![CDATA[Kael Rowan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaelr/2010/08/05/zoomableapplication1-scale-and-offset/</guid>
      <description><![CDATA[For the first entry in the series of examples using the ZoomableCanvas, I&rsquo;ll start off with...]]></description>
      <content:encoded><![CDATA[<p>For the first entry in the series of examples using the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2010/07/29/zoomablecanvas.aspx">ZoomableCanvas</a></span></span>, I&rsquo;ll start off with just the basics: <span style="font-family: Consolas, Courier;">Scale</span> and <span style="font-family: Consolas, Courier;">Offset</span>.&nbsp; I&rsquo;ll start by creating a brand new app, renaming it from WpfApplication1 to ZoomableApplication1, and adding a reference to a class library that I created after downloading the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2010/07/29/zoomablecanvas.aspx">ZoomableCanvas</a></span></span> source code and its dependencies that were listed at the bottom of this post: <a href="http://blogs.msdn.com/b/kaelr/archive/2010/07/29/zoomablecanvas.aspx" title="http://blogs.msdn.com/b/kaelr/archive/2010/07/29/zoomablecanvas.aspx">http://blogs.msdn.com/b/kaelr/archive/2010/07/29/zoomablecanvas.aspx</a>.</p>
<p>The next thing I&rsquo;ll do is get rid of the default <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;</span></span> and replace it with a <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ZoomableCanvas</span><span style="color: blue">&gt;</span></span> with some children, like this:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Window </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Class</span><span style="color: blue">="ZoomableApplication1.MainWindow"
        </span><span style="color: red">xmlns</span><span style="color: blue">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        </span><span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">x</span><span style="color: blue">="http://schemas.microsoft.com/winfx/2006/xaml"
        </span><span style="color: red">Title</span><span style="color: blue">="MainWindow" </span><span style="color: red">Height</span><span style="color: blue">="350" </span><span style="color: red">Width</span><span style="color: blue">="525"&gt;
    &lt;</span><span style="color: #a31515">ZoomableCanvas</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">Rectangle </span><span style="color: red">Canvas.Top</span><span style="color: blue">="0" </span><span style="color: red">Canvas.Left</span><span style="color: blue">="0"
                   </span><span style="color: red">Width</span><span style="color: blue">="30" </span><span style="color: red">Height</span><span style="color: blue">="40" </span><span style="color: red">Fill</span><span style="color: blue">="LightBlue"/&gt;

        &lt;</span><span style="color: #a31515">Button    </span><span style="color: red">Canvas.Top</span><span style="color: blue">="10" </span><span style="color: red">Canvas.Left</span><span style="color: blue">="40"
                   </span><span style="color: red">Content</span><span style="color: blue">="Hello, ZoomableCanvas!"/&gt;

        &lt;</span><span style="color: #a31515">Calendar  </span><span style="color: red">Canvas.Top</span><span style="color: blue">="40" </span><span style="color: red">Canvas.Left</span><span style="color: blue">="10"
                   </span><span style="color: red">DisplayDate</span><span style="color: blue">="6/18/2008"/&gt;
    &lt;/</span><span style="color: #a31515">ZoomableCanvas</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">Window</span><span style="color: blue">&gt;
</span></span></pre>
<p>And as you&rsquo;d expect with a regular <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Canvas</span><span style="color: blue">&gt;</span></span>, this is the result:</p>
<p><iframe width="200" src="http://research.microsoft.com/en-us/um/people/kaelr/apps/ZoomableApplication1-1.xbap" height="215"></iframe><br /><span style="font-size: xx-small;">(I&rsquo;ve embedded the sample as an XBAP in an <span style="font-family: Consolas, Courier;">&lt;iframe&gt;</span> above this line, so you should see a live sample and be able to interact with it if you&rsquo;re using Internet Explorer and have .NET 4.0 installed.)</span></p>
<p>So far this is no different from a regular <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Canvas</span><span style="color: blue">&gt;</span></span>, so lets start off by setting the <span style="font-family: Consolas, Courier;">Scale</span> and <span style="font-family: Consolas, Courier;">Offset</span> directly in the XAML, like this:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;">    <span style="color: blue">&lt;</span><span style="color: #a31515">ZoomableCanvas </span><span style="color: red">Scale</span><span style="color: blue">=".5" </span><span style="color: red">Offset</span><span style="color: blue">="-100,0"&gt;
</span></span></pre>
<p><iframe width="200" src="http://research.microsoft.com/en-us/um/people/kaelr/apps/ZoomableApplication1-2.xbap" height="110"></iframe></p>
<p>You&rsquo;ll notice that the elements have shrunk by half and moved to the right by 100 pixels.&nbsp; But this is not normally how you&rsquo;d set <span style="font-family: Consolas, Courier;">Scale</span> and <span style="font-family: Consolas, Courier;">Offset</span>.&nbsp; Normally you&rsquo;d change them dynamically; for example you might want to set <span style="font-family: Consolas, Courier;">Scale</span> with a zoom slider, like this:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;">    <span style="color: blue">&lt;</span><span style="color: #a31515">DockPanel</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">Slider </span><span style="color: red">Minimum</span><span style="color: blue">=".1" </span><span style="color: red">Maximum</span><span style="color: blue">="2" </span><span style="color: red">Orientation</span><span style="color: blue">="Vertical"
                </span><span style="color: red">Value</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">ElementName</span><span style="color: blue">=MyCanvas, </span><span style="color: red">Path</span><span style="color: blue">=Scale}"/&gt;

        &lt;</span><span style="color: #a31515">ZoomableCanvas </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">="MyCanvas"&gt;
            &lt;</span><span style="color: #a31515">Rectangle </span><span style="color: red">Canvas.Top</span><span style="color: blue">="0" </span><span style="color: red">Canvas.Left</span><span style="color: blue">="0"
                </span><span style="color: red">Width</span><span style="color: blue">="30" </span><span style="color: red">Height</span><span style="color: blue">="40" </span><span style="color: red">Fill</span><span style="color: blue">="LightBlue"/&gt;

            &lt;</span><span style="color: #a31515">Button    </span><span style="color: red">Canvas.Top</span><span style="color: blue">="10" </span><span style="color: red">Canvas.Left</span><span style="color: blue">="40"
                </span><span style="color: red">Content</span><span style="color: blue">="Hello, ZoomableCanvas!"/&gt;

            &lt;</span><span style="color: #a31515">Calendar  </span><span style="color: red">Canvas.Top</span><span style="color: blue">="40" </span><span style="color: red">Canvas.Left</span><span style="color: blue">="10"
                </span><span style="color: red">DisplayDate</span><span style="color: blue">="6/18/2008"/&gt;
        &lt;/</span><span style="color: #a31515">ZoomableCanvas</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">DockPanel</span><span style="color: blue">&gt;
</span></span></pre>
<p><iframe width="220" src="http://research.microsoft.com/en-us/um/people/kaelr/apps/ZoomableApplication1-3.xbap" height="215"></iframe></p>
<p>But of course it&rsquo;s much more natural to use the mouse wheel to zoom and click and drag to pan.&nbsp; So let&rsquo;s <span style="font-family: Consolas, Courier;"><span style="color: blue">override</span></span> the <span style="font-family: Consolas, Courier;">OnMouseWheel</span> and <span style="font-family: Consolas, Courier;">OnMouseMove</span> events on our <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Window</span></span> to control the <span style="font-family: Consolas, Courier;">Scale</span> and <span style="font-family: Consolas, Courier;">Offset</span> as well:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;"><span style="color: blue">protected override void </span>OnMouseWheel(<span style="color: #2b91af">MouseWheelEventArgs </span>e)
{
    <span style="color: blue">var </span>x = <span style="color: #2b91af">Math</span>.Pow(2, e.Delta / 3.0 / <span style="color: #2b91af">Mouse</span>.MouseWheelDeltaForOneLine);
    MyCanvas.Scale *= x;
}

<span style="color: blue">private </span><span style="color: #2b91af">Point </span>LastMousePosition;

<span style="color: blue">protected override void </span>OnMouseMove(<span style="color: #2b91af">MouseEventArgs </span>e)
{
    <span style="color: blue">var </span>position = e.GetPosition(<span style="color: blue">this</span>);
    <span style="color: blue">if </span>(e.LeftButton == <span style="color: #2b91af">MouseButtonState</span>.Pressed)
    {
        MyCanvas.Offset -= position - LastMousePosition;
    }
    LastMousePosition = position;
}
</span></pre>
<p><iframe width="220" src="http://research.microsoft.com/en-us/um/people/kaelr/apps/ZoomableApplication1-4.xbap" height="215"></iframe></p>
<p>The <span style="font-family: Consolas, Courier;">OnMouseWheel</span> method takes the distance that the mouse wheel was turned (which is given by <span style="font-family: Consolas, Courier;">e.Delta</span>), divides it by 3 since by default Windows expects to scroll 3 &ldquo;lines&rdquo; per tick, and then divides that amount by the amount of <span style="font-family: Consolas, Courier;">Delta</span> that represents each &ldquo;line&rdquo;.&nbsp; That value could be <em>negative</em> since <span style="font-family: Consolas, Courier;">e.Delta</span> is negative when the mouse wheel is rotated backwards, so raising 2 to that power gives us a nice value above or below 1.0, but never below 0.&nbsp; Then we simply adjust the scale by multiplying it by that amount.</p>
<p>The <span style="font-family: Consolas, Courier;">OnMouseMove</span> method is about equally as simple.&nbsp; It just keeps track of the last mouse position, and if the mouse button is held down when you drag the mouse then it adjusts <span style="font-family: Consolas, Courier;">Offset</span> by the amount you dragged it.&nbsp; Of course, we aren&rsquo;t setting <span style="font-family: Consolas, Courier;">e.Handled = <span style="color: blue">true</span></span> or doing any mouse capturing in this tiny example, so you get some interesting interactions with other elements on the canvas that try to handle the mouse as well.&nbsp; Try dragging the zoom slider remaining from the previous example for an interesting effect!</p>
<p>That&rsquo;s about it for <span style="font-family: Consolas, Courier;">Scale</span> and <span style="font-family: Consolas, Courier;">Offset</span>.&nbsp; In the upcoming posts I&rsquo;ll show some more examples of mouse handling, including having the canvas zoom in and out &ldquo;around the mouse&rdquo;, which means that the point under the mouse cursor will stay &ldquo;fixed&rdquo; while the other points on the canvas move in and out relative to it as you zoom.&nbsp; You can take a look at <a href="http://maps.bing.com">Bing maps</a> to see what I mean.</p>
<p>In the mean time, I&rsquo;ve attached the ZoomableApplication1 project to this post, and it includes the class library that I mentioned in the beginning.&nbsp; The class library simply contains the source code files listed at bottom of this post: <a href="http://blogs.msdn.com/b/kaelr/archive/2010/07/29/zoomablecanvas.aspx" title="http://blogs.msdn.com/b/kaelr/archive/2010/07/29/zoomablecanvas.aspx">http://blogs.msdn.com/b/kaelr/archive/2010/07/29/zoomablecanvas.aspx</a>, but if you don&rsquo;t want to go download all the source files yourself then you can just grab the ZoomableCanvas.dll assembly from here since I&rsquo;ve already done the work for you.&nbsp; Enjoy!</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/04/68/45/ZoomableApplication1.zip" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-04-68-45/ZoomableApplication1.zip">ZoomableApplication1.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>ZoomableCanvas</title>
      <link>https://docs.microsoft.com/archive/blogs/kaelr/zoomablecanvas</link>
      <pubDate>Thu, 29 Jul 2010 03:14:00 GMT</pubDate>
      <dc:creator><![CDATA[Kael Rowan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaelr/2010/07/29/zoomablecanvas/</guid>
      <description><![CDATA[ZoomableCanvas is the Panel that displays almost all of the elements in Code Canvas.&nbsp; Code...]]></description>
      <content:encoded><![CDATA[<p><span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> is the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Panel</span></span> that displays almost all of the elements in <a href="http://blogs.msdn.com/b/kaelr/archive/2009/03/26/code-canvas.aspx">Code Canvas</a>.&nbsp; Code Canvas is actually made up of several <em>layers</em> of <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span>es that are stacked on top of each other, and they are synchronized by simply sharing the same values for <span style="font-family: Consolas, Courier;">Scale</span> and <span style="font-family: Consolas, Courier;">Offset</span>.&nbsp; <span style="font-family: Consolas, Courier;">Scale</span> and <span style="font-family: Consolas, Courier;">Offset</span> are the driving forces behind the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span>, because they are what control the location (and sometimes the size) of the elements when they are shown on the screen.</p>
<p>The reason that <span style="font-family: Consolas, Courier;">Scale</span> only <em>sometimes</em> controls the size of the elements on screen is because the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> has a <span style="font-family: Consolas, Courier;"><span style="color: blue">bool</span></span> property called <span style="font-family: Consolas, Courier;">ApplyTransform</span>, and if <span style="font-family: Consolas, Courier;">ApplyTransform = <span style="color: blue">false</span></span> then the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> will not affect the size of elements at all.&nbsp; <span style="font-family: Consolas, Courier;">ApplyTransform</span> is set to <span style="font-family: Consolas, Courier;"><span style="color: blue">true</span></span> by default, which means you get scaling automatically for free, but sometimes you may wish to turn it off so you can do custom effects instead, such as <a href="http://www.infovis-wiki.net/index.php/Semantic_Zoom">semantic zoom</a>.&nbsp; When <span style="font-family: Consolas, Courier;">ApplyTransform = <span style="color: blue">false</span></span>, the <span style="font-family: Consolas, Courier;">Scale</span> will still affect the <em>position</em> of the elements (i.e. they get closer together as you zoom out, and farther apart as you zoom in), but changing the <em>size</em> of the elements is up to you.&nbsp; If you forget to change the size, then you&rsquo;ll end up with your elements appearing to &ldquo;float above&rdquo; the canvas, and in fact the search results and definition labels in Code Canvas do exactly that on purpose.&nbsp; Check out the various Code Canvas videos to see that effect in action.</p>
<p><span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> is similar to Chris Lovett&rsquo;s <a href="http://blogs.msdn.com/b/jgoldb/archive/2008/03/08/performant-virtualized-wpf-canvas.aspx">VirtualCanvas</a>, but it has some important differences.&nbsp; The main difference is that <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> is meant to feel like a built-in WPF component, just like the default <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Canvas</span></span>, and so it supports the three most common methods of populating a <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Panel</span></span> in WPF:</p>
<p>1. Adding children directly to the canvas, either via the <span style="font-family: Consolas, Courier;">Children</span> property or via XAML. <br />2. Adding children with the <span style="font-family: Consolas, Courier;">Items</span> property of a parent <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ItemsControl</span></span> (like a <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ListBox</span></span>). <br />3. Binding to a data source with the <span style="font-family: Consolas, Courier;">ItemsSource</span> property of a parent <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ItemsControl</span></span>.</p>
<p>In the first case, you can use it exactly how you&rsquo;d use a normal <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Canvas</span></span>:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;">    <span style="color: blue">&lt;</span><span style="color: #a31515">ZoomableCanvas</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">Rectangle </span><span style="color: red">Canvas.Top</span><span style="color: blue">="10" </span><span style="color: red">Canvas.Left</span><span style="color: blue">="20"
                   </span><span style="color: red">Width</span><span style="color: blue">="30" </span><span style="color: red">Height</span><span style="color: blue">="40" </span><span style="color: red">Fill</span><span style="color: blue">="LightBlue"/&gt;

        &lt;</span><span style="color: #a31515">Button    </span><span style="color: red">Canvas.Top</span><span style="color: blue">="10" </span><span style="color: red">Canvas.Left</span><span style="color: blue">="60"
                   </span><span style="color: red">Content</span><span style="color: blue">="Hello, ZoomableCanvas!"/&gt;

        &lt;</span><span style="color: #a31515">Calendar  </span><span style="color: red">Canvas.Top</span><span style="color: blue">="40" </span><span style="color: red">Canvas.Left</span><span style="color: blue">="60"
                   </span><span style="color: red">DisplayDate</span><span style="color: blue">="6/18/2008"/&gt;
    &lt;/</span><span style="color: #a31515">ZoomableCanvas</span><span style="color: blue">&gt;
</span></span></pre>
<p>In the second case, you can also use it in exactly the same way that you would if you were to use a normal <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Canvas</span></span> within an <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ItemsControl</span></span>:</p>
<pre style="word-wrap: break-word; white-space: pre-wrap"><span style="font-family: Consolas, Courier;">    <span style="color: blue">&lt;</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">ListBox.ItemsPanel</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">ItemsPanelTemplate</span><span style="color: blue">&gt;
                &lt;</span><span style="color: #a31515">ZoomableCanvas</span><span style="color: blue">/&gt;
            &lt;/</span><span style="color: #a31515">ItemsPanelTemplate</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">ListBox.ItemsPanel</span><span style="color: blue">&gt;

        &lt;</span><span style="color: #a31515">ListBox.ItemContainerStyle</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">Style</span><span style="color: blue">&gt;
                &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="Canvas.Top"
                        </span><span style="color: red">Value</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">Path</span><span style="color: blue">=Content.(Canvas.Top),
                                </span><span style="color: red">RelativeSource</span><span style="color: blue">={</span><span style="color: #a31515">RelativeSource </span><span style="color: red">Self</span><span style="color: blue">}}"/&gt;
                
                &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="Canvas.Left"
                        </span><span style="color: red">Value</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">Path</span><span style="color: blue">=Content.(Canvas.Left),
                                </span><span style="color: red">RelativeSource</span><span style="color: blue">={</span><span style="color: #a31515">RelativeSource </span><span style="color: red">Self</span><span style="color: blue">}}"/&gt;
            &lt;/</span><span style="color: #a31515">Style</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">ListBox.ItemContainerStyle</span><span style="color: blue">&gt;

        &lt;</span><span style="color: #a31515">ListBox.Items</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">Rectangle </span><span style="color: red">Canvas.Top</span><span style="color: blue">="10" </span><span style="color: red">Canvas.Left</span><span style="color: blue">="20"
                       </span><span style="color: red">Width</span><span style="color: blue">="30" </span><span style="color: red">Height</span><span style="color: blue">="40" </span><span style="color: red">Fill</span><span style="color: blue">="LightBlue"/&gt;

            &lt;</span><span style="color: #a31515">Button    </span><span style="color: red">Canvas.Top</span><span style="color: blue">="10" </span><span style="color: red">Canvas.Left</span><span style="color: blue">="60"
                       </span><span style="color: red">Content</span><span style="color: blue">="Hello, ZoomableCanvas!"/&gt;

            &lt;</span><span style="color: #a31515">Calendar  </span><span style="color: red">Canvas.Top</span><span style="color: blue">="40" </span><span style="color: red">Canvas.Left</span><span style="color: blue">="60"
                       </span><span style="color: red">DisplayDate</span><span style="color: blue">="6/18/2008"/&gt;
        &lt;/</span><span style="color: #a31515">ListBox.Items</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;
</span></span></pre>
<p>&nbsp;</p>
<p>The fact that you have to set <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox.ItemContainerStyle</span><span style="color: blue">&gt;</span></span> is a bit ugly, but it&rsquo;s not something caused by <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span>.&nbsp; Since <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ItemsControl</span></span>s always wrap their items in <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ContentPresenter</span></span>s, you end up with an extra level of indirection between the item and the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Panel</span></span>, so you have to use a <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">Style</span><span style="color: blue">&gt;</span></span> on the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ContentPresenter</span></span> to make the connection.&nbsp; This is a well-known issue for anyone who has ever tried to use a <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Grid</span></span> or a <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">DockPanel</span></span> in a <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ListBox</span></span>, for example.</p>
<p>The third case is probably the most likely, and it&rsquo;s basically the same as the last one except that you set <span style="font-family: Consolas, Courier;"><span style="color: red">ItemsSource</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: blue">...}"</span></span> instead of specifying the <span style="font-family: Consolas, Courier;"><span style="color: blue">&lt;</span><span style="color: #a31515">ListBox.Items</span><span style="color: blue">&gt;</span></span> directly.&nbsp; This is also the only way to get data virtualization.</p>
<p>Speaking of virtualization, <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> supports both kinds of virtualization: UI virtualization and data virtualization.&nbsp; UI virtualization is when you have lots of data items loaded into memory (plain .NET objects, not <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Visual</span></span>s), but you only create the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Visual</span></span>s for those items that can be seen on the screen.&nbsp; Data virtualization is when you don&rsquo;t even load all of the data items into memory; you only load a subset of the data, but you &ldquo;pretend&rdquo; that the full data set is there.&nbsp; You can even have both kinds of virtualization going on at once.&nbsp; For example, imagine you&rsquo;re creating an application that draws a social networking graph of all of the users on the Internet.&nbsp; Your back-end database would likely have millions (or billions) of nodes and edges, but someone using a 24&rdquo; monitor would realistically only be able to see a few thousand at once.&nbsp; Your users probably don&rsquo;t have enough RAM to load the entire dataset into memory, but they probably don&rsquo;t have enough bandwidth to issue thousands of queries on-the-fly as they pan and zoom around.&nbsp; So you can use data virtualization to fetch and cache only some moderate portion of the full data set (e.g. a couple hundred thousand nodes around the neighborhood they&rsquo;re viewing), and use UI virtualization to only create <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Visual</span></span>s for the few hundreds of nodes that are actually on their screen.</p>
<p><span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> provides some default UI virtualization for free out of the box by using <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2009/04/27/virtualpanel.aspx">VirtualPanel</a></span></span> and <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2009/05/21/priorityquadtree.aspx">PriorityQuadTree</a></span></span>, both posted previously on my blog.&nbsp; You can also improve the performance even further by having your data source implement <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span>.<span style="color: #2b91af">ISpatialItemsSource</span></span>.&nbsp; When the value you gave to <span style="font-family: Consolas, Courier;"><span style="color: red">ItemsSource</span></span> implements <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ISpatialItemsSource</span></span>, the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> will call the <span style="font-family: Consolas, Courier;">Query</span> method instead of enumerating over the whole list.&nbsp; The <span style="font-family: Consolas, Courier;">Query</span> method simply takes the current viewbox as a parameter and returns the indexes of the items that fall within that viewbox.&nbsp; This is also known as a <a href="http://en.wikipedia.org/wiki/Spatial_index">spatial index</a>, and it&rsquo;s what you can use to implement data virtualization as well.&nbsp; If you don&rsquo;t implement <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ISpatialItemsSource</span></span>, then the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> will build its own spatial index internally using the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2009/05/21/priorityquadtree.aspx">PriorityQuadTree</a></span></span>, but it will have to enumerate the whole data list and create each <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Visual</span></span> one time to do it.&nbsp; The <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Visual</span></span>s that are off-screen will quickly be re-virtualized, but the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> needs to create them temporarily so that it can inspect the <span style="font-family: Consolas, Courier;"><span style="color: red">Canvas.Top</span></span> and <span style="font-family: Consolas, Courier;"><span style="color: red">Canvas.Left</span></span> properties to see where the item needs to go.&nbsp; By having your data source implement <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ISpatialItemsSource</span></span>, you can completely bypass this step.</p>
<p>A final thing to keep in mind is that, although <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> provides easy-to-use properties like <span style="font-family: Consolas, Courier;">Offset</span>, <span style="font-family: Consolas, Courier;">Scale</span>, and even <span style="font-family: Consolas, Courier;">Viewbox</span>, <span style="font-family: Consolas, Courier;">Stretch</span>, and <span style="font-family: Consolas, Courier;">StretchDirection</span>, it does not provide any default keyboard or mouse gesture handling.&nbsp; The <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> is meant to be like any other built-in WPF component, and it&rsquo;s expected that each application will be responsible for handling their own user input differently.&nbsp; For example, the built-in <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">Canvas</span></span> doesn&rsquo;t provide mouse handling to let users drag items around on the canvas, even though that&rsquo;s what most people do with it.&nbsp; In the same vein, <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> doesn&rsquo;t provide any mouse handling for dragging items or panning or zooming.&nbsp; But I will be posting a blog series on the various cool things you can do with <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span>, and you will quickly see that adding these things is a piece of cake.</p>
<p>I&rsquo;ve attached the full source code for <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> to this post, but it relies on the <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2009/04/27/virtualpanel.aspx">VirtualPanel</a></span></span>, <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2009/05/21/priorityquadtree.aspx">PriorityQuadTree</a></span></span>, <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2008/05/12/mathextensions.aspx">MathExtensions</a></span></span>, and <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2010/04/09/linkedlist-findnext-and-findprevious.aspx">LinkedListExtensions</a></span></span> from the other posts on my blog.&nbsp; Once you&rsquo;ve downloaded those files and put them all in a class library, you can throw in some <span style="font-family: Consolas, Courier;"><span style="color: #2b91af"><a href="http://blogs.msdn.com/b/kaelr/archive/2008/05/21/presentation-more.aspx">XmlnsDefinitions</a></span></span> and you&rsquo;ll have a <span style="font-family: Consolas, Courier;"><span style="color: #2b91af">ZoomableCanvas</span></span> that looks like it came straight from WPF!&nbsp; Enjoy!</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/04/57/41/ZoomableCanvas.cs" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-04-57-41/ZoomableCanvas.cs">ZoomableCanvas.cs</a></p>]]></content:encoded>
    </item>
  </channel>
</rss>