30 October 2012

Data binding shapes to the new Windows Phone 8 Map control (and more)

A little history

When I accepted the invitation from MADNbe to talk about Maps and MVVM on September 20 early in the summer (or what was supposed to be the summer) of 2012 the actual release date for the Windows Phone SDK 8.0 was still a mystery. As it gradually became clear the SDK would not be available at the date my talk was scheduled, I devised a plan B and in stead talked about Windows Phone 7 mapping and how to port this code and knowledge to Windows 8. I also wrote a blog post I wrote about it. Now the funny thing is - the Windows Phone 8 mapping control and the Windows 8 Bing Maps control show some remarkable similarities. So if you read this article and think “Huh? I’ve read this before” that’s entirely possible! 

Hello 8 WorldSo world in general, and Belgium in particular, meet the new Hello World, Windows Phone 8 style!

Windows Phone 7 map binding recap

Not going to happen - I am not going to repeat myself for the sake of content ;-). In the the Windows 8 article I give a short recap of how you can bind to a Windows Phone 7 map, using templates. I’d suggest you read that if you haven’t done so already ;-). By the way, the sample solution contained with this project is mostly the same as the sample Windows Phone 7 application I use in my talk. I upgraded to Windows Phone but did not even bother to change the libraries I used. (like MVVMLight, Phone7.Fx or my own wp7nl library). That’s still Windows Phone 7 code and you call that code from Windows Phone 8 without any problem. Very soon I hope to publish updates for the libraries specific to the platform, and you will see them appearing in your NuGet package manager. The only thing you have to keep in mind is that the app no longer runs in quirks mode once you upgraded to Windows Phone 8. That means – if your library code does something funky that has a different behavior under Windows Phone 8, the platform is not going to help you keep that funky behavior  - unlike when you run a (real) Windows Phone 7 app on it.

Data binding and the new map control

Without cheering overly loud for ‘my’ home team, I actually think the Windows Phone mapping team actually has done a better job on this part than their Windows 8 brethren. That’s actually not so very hard, as the Windows 8 Bing Maps control does not support data binding at all. The Windows Phone 8 control actually (still) supports the binding of Center and ZoomLevel, as well as the new properties CartographicMode, LandMarksEnabled, Heading and Pitch, – “Heading” being the direction of the top of the map, default 0, being North – and Pitch the viewing angle of the map (normally zero, or ‘straight from above’). And probably some more I haven’t used yet.

But as far as drawing shapes on the maps are concerned, we are in the same boat as in Windows 8:

  • The shapes the control draws cannot be templated. They are apparently just projections of something native (as is the map itself).
  • There are only two kinds of shapes: MapPolygon and MapPolyline, both descending from MapElement (as opposed to MapShape in Windows 8), which in turn descends from DependencyObject – so I can use the same trick again – storing data in attached dependency properties.

To solve this, I use the same approach as I did in Windows 8: apply behaviors. Only that’s a lot easier now because unlike Windows 8, Windows Phone 8 supports behaviors out of the box.

Introducing MapShapeDrawBehavior for Windows Phone 8

This behavior is, just like it’s Windows 8 brother, called MapShapeDrawBehavior. It’s use is quite similar:

<Maps:Map x:Name="map" CartographicMode="Road">
  <i:Interaction.Behaviors>
    <MapBinding:MapShapeDrawBehavior LayerName="Roadblocks" 
       ItemsSource="{Binding RoadBlocks}" 
       PathPropertyName="Geometry">
      <MapBinding:MapShapeDrawBehavior.EventToCommandMappers>
        <MapBinding:EventToCommandMapper EventName="Tap" 
                                         CommandName="SelectCommand"/>
      </MapBinding:MapShapeDrawBehavior.EventToCommandMappers>
      <MapBinding:MapShapeDrawBehavior.ShapeDrawer>
        <MapBinding:MapPolylineDrawer Color="Green" Width="10"/>
      </MapBinding:MapShapeDrawBehavior.ShapeDrawer>
    </MapBinding:MapShapeDrawBehavior>
  </i:Interaction.Behaviors>
</Maps:Map>

The only difference, in fact, with the Windows 8 behavior is that there is not a TapCommand property but an EventMapper collection. That is because unlike the Windows 8 map shapes, Windows Phone 8 shapes don’t support events at all. These are events of the map. There aren’t any layers for shapes too – there is just a MapElements collection that you can add shapes to.

So for every category of objects you define a behavior; in this case the road blocks (the green line on the app sceenshot above). This translates conceptually to a ‘layer’. Then you need to define three things per layer:

  • Which property in the item view model contains the Path – this is the terminology for a MapElement collection of points. This is of type GeoCoordinateCollection.
  • A drawer. A drawer is a concept I made up myself. It’s a class that creates a shape from a collection of points contained in a GeoCoordinateCollection. It’s my way to make something that’s not templatable more or less configurable and the idea behind is exactly the same as for Windows 8.
  • What command in the item view model (in this case, a RoadBlockViewModel) must be called when a GestureEvent is called on the map. This can be either Tap or DoubleTap. You do this by adding an EventToCommandMapper to the EventToCommandMappers list.

          This behavior comes, just like it’s Windows 8 brother,  the three out-of-the box standard drawers: MapPolylineDrawer, MapPolygonDrawer, and MapStarDrawer. The last one draws a configurable star shaped polygon around a point – since map shapes cannot be points by themselves. A drawer needs only to implement one method:

          public override MapElement CreateShape(object viewModel, LocationCollection path)

          The basic drawers don’t do anything with the view model: they just take the settings from XAML. You can write your own if you want for instance return a shape of a different color based upon view model values. Thematic mapping again, just like I said last time.

          If you just want to use the behavior, download the sample solution, rip the Wp8nl.Contrib project from it and use it. It just needs a reference to System.Windows.Interactivity.dll, that’s about all.

          Some technical details

          As the inner workings of the behavior are almost identical to that of their Windows 8 counterparts, I am not going to recap everything again. The trick is the same: view models and layer names are stored in and retrieved from attached dependency properties that are attached to the shapes themselves - the behavior uses this how to hold view models and map shapes together, and which shape belongs to which layer. For the technically interested I will stress a few small points. First of all, I already said the map elements themselves don’t have any events. Therefore, I have to attach events to the map, using the “AddEventMappings” method that’s loaded when the behavior’s OnLoad is called:
          private void AddEventMappings()
          {
            foreach (var mapper in EventToCommandMappers)
            {
              var evt = AssociatedObject.GetType().GetRuntimeEvent(mapper.EventName);
              if (evt != null)
              {
                AddEventMapping(mapper);
              }
            }
          }
          
          private void AddEventMapping(EventToCommandMapper mapper)
          {
            Observable.FromEvent<GestureEventArgs>(AssociatedObject, mapper.EventName)
              .Subscribe(se =>
               {
                 var gestureArgs = se.EventArgs;
                 if (gestureArgs != null)
                 {
                   var shape = 
                      AssociatedObject.GetMapElementsAt(
                         gestureArgs.GetPosition(AssociatedObject)).FirstOrDefault(
                           p => MapElementProperties.GetLayerName(p)==LayerName);
                   if (shape != null)
                   {
                     FireViewmodelCommand(
                       MapElementProperties.GetViewModel(shape), mapper.CommandName);
                   }
                 }
               });
          }

          So this works fundamentally different from it’s Windows 8 counterpart: not the shapes respond to events, but the map does so, and reports the shapes found at a location of the tap or the doubletap. The shapes in question can be retrieved using the map’s GetMapElementsAt method. And then I select the first shape I find that has the same layer name in it’s LayerName attached dependency property as the behavior. Note this filter is necessary: the map reports the shapes and it reports all of them - since there is no real layer structure the map has no notion of which behavior put the shape on the map. And you don’t want every behavior reporting all other shapes that happen to be on the same location as well – that would result in double events. But if the behavior finds a hit, it calls the FireViewModelCommand, which is essentially the same as in Windows 8, and it shows the window with alphanumeric info. That part has not been changed at all.

          The rest of the behavior is mainly concerned with adding, removing and replacing shapes again. I would suggest you’d study that if you are interested in how to respond to the various events of an ObservableCollection. To prove that data binding actually works, you can open the menu and select “change dhl building”.  That’s the most eastward building on the map. If you choose that, you will actually see the building change shape. The only thing the TestChangedShapeCommand command - that’s called when you hit that menu item – does, it change a building’s geometry property. The image on the map is updated automatically.

          Some concluding observations

          Somewhere down in the guts of Windows Phone 8 there’s a native control, and I very much think both it and it’s Bing Maps control for Windows 8 counterpart are of the same breed. Both have similar, yet subtly different projections to managed code. As I already mentioned – in Windows 8 the shapes descend from MapShape, in Windows Phone 8 from MapElement. In addition, Windows Phone Map Elements support StrokeColor, StrokeThickness and StrokeDash – no such thing on Windows 8 - one more cheer for the Windows Phone team ;). But neither are supporting complex shapes and things like donuts (polygons with holes in it). These are the hallmarks of the real heavy duty GIS systems like the stuff Cadcorp. ESRI et al are making.

          Also important when sharing code is to note the following:

          • In Windows Phone 7, we made shapes from a LocationCollection, which is a collection of GeoCoordinate
          • In Windows Phone 8, shapes are created from a GeoCoordinateCollection, which is a collection of GeoCoordinate
          • In Windows 8, shapes are created from a LocationCollection which is a collection of Location.

          So both platforms refactored the Locations and their collection, and both in opposite ways. This can be solved by using converters or a generic subclass specific for both platforms but I leave things like that as exercise for the reader. The fun thing is: once again it shows that a lot of code can be reused as long as you keep application and business logic in models and view models – that way, you only have to deal with user interface and platform considerations, but your basic app structure stays intact. Once more: three cheers for MVVM.

          And as usual you can download the sample solution. I will shortly add this stuff to the Windows Phone 8 specific version of the wp7nl library on CodePlex

          Happy mapping on Windows Phone 8!

          Introducing the new Windows Phone 8 Map control

          The time is finally there: the Windows Phone SDK 8.0 is out, and now we can finally talk about all the great news things for developers that this new SDK brings, and I’ll start that right now. And I don’t think it will surprise anyone who knows me that the first thing I did was looking at the much-rumored new maps control.

          map1I was not disappointed. In general, just two words: super slick. The very embodiment of fast and fluid. What Windows Phone 8 brings to the mapping table made by geo hart skip and is nothing short of dramatic. Think the Nokia drive map on your Windows Phone 7. On steroids. As a control. For you to use in your apps. With downloadable maps for use offline. I have seen it run on actual hardware and for me as a GIS buff, used to the fact that maps stuff usually take a lot of processing power and doesn’t necessary always go super fast, this was a serious nerdgasm. So I created a little app to show off the very basics of this map control. It allows you to select the various map modes, as well to to select map heading and pitch. Heading is the direction the top of the map is pointing – in Bing Maps this was always “North”, and Pitch is how you are looking on the map. If that’s 0, you are looking straight from above.

          Now the important the thing about Windows Phone 8 is that the team really went out of their way to make sure code is backwards compatible. That means that not only the new maps control is in the framework, but also Ye Olde Bing Maps control. This can lead to some confusing situations. The important thing to remember when working with the new map control is

          • The (old) Bing Maps control stuff is in namespace Microsoft.Phone.Controls.Maps
          • The new map control stuff in in namespace Microsoft.Phone.Maps.Controls.

          So “Controls” and “Maps” are swapped. I always keep in mind “maps first” as a mnemonic to remember which namespace to use. Especially when you are using ReSharper or a tool like it that most helpfully offers you to add namespaces and references (again) can really get you caught on the wrong foot, so pay attention.

          I started out creating a “New Windows Phone App”, selected OS 8.0 (of course), fired up the Library Package Manager and downloaded my wp7nl library. This gives MVVMLight and some other stuff I need for my sample. At the moment of this writing this is still Windows Phone 7 code but this will run fine (of course this all will be updated shortly). The only thing you need to take care of is that you delete the references to Windows Phone Controls.dll and Windows Phone Controls.Maps.dll the package makes.

          First step is to make a simple view model describing the cartographic modes the new map control supports:

          using GalaSoft.MvvmLight;
          using Microsoft.Phone.Maps.Controls;
          
          namespace MvvmMapDemo1.ViewModels
          {
            public class MapMode : ViewModelBase
            {
              private string name;
              public string Name
              {
                get { return name; }
                set
                {
                  if (name != value)
                  {
                    name = value;
                    RaisePropertyChanged(() => Name);
                  }
                }
              }
          
              private MapCartographicMode cartographicMode;
              public MapCartographicMode CartographicMode
              {
                get { return cartographicMode; }
                set
                {
                  if (cartographicMode != value)
                  {
                    cartographicMode = value;
                    RaisePropertyChanged(() => CartographicMode);
                  }
                }
              }
            }
          }
          

          The main view is basically some properties and a little bit of logic. First part handles the setup and the properties for displaying and selecting the cartographic map modes:

          using System;
          using System.Collections.ObjectModel;
          using System.Device.Location;
          using GalaSoft.MvvmLight;
          using Microsoft.Phone.Maps.Controls;
          
          namespace MvvmMapDemo1.ViewModels
          {
            public class MapViewModel : ViewModelBase
            {
              public MapViewModel()
              {
                modes = new ObservableCollection<MapMode>
                {
                  new MapMode 
                    {CartographicMode = MapCartographicMode.Road, Name = "Road"},
                  new MapMode 
                    {CartographicMode = MapCartographicMode.Aerial, Name = "Aerial"},
                  new MapMode 
                   {CartographicMode = MapCartographicMode.Hybrid, Name = "Hybrid"},
                  new MapMode
                   {CartographicMode = MapCartographicMode.Terrain, Name = "Terrain"}
                };
                selectedMode = modes[0];
              }
              
              private MapMode selectedMode;
              public MapMode SelectedMode
              {
                get { return selectedMode; }
                set
                {
                  if (selectedMode != value)
                  {
                    selectedMode = value;
                    RaisePropertyChanged(() => SelectedMode);
                  }
                }
              }
          
              private ObservableCollection<MapMode> modes;
              public ObservableCollection<MapMode> Modes
              {
                get { return modes; }
                set
                {
                  if (modes != value)
                  {
                    modes = value;
                    RaisePropertyChanged(() => Modes);
                  }
                }
              }
            }
          }
          

          The only important part about this is that there must be an initially selected mode, as the control does not take it very well if the mode is forcibly set to null by the data binding.

          At little bit more interesting are the next two properties of the view model, which control heading and pitch:

          private double pitch;
          public double Pitch
          {
            get { return pitch; }
            set
            {
              if (Math.Abs(pitch - value) > 0.05)
              {
                pitch = value;
                RaisePropertyChanged(() => Pitch);
              }
            }
          }
          
          private double heading;
          public double Heading
          {
            get { return heading; }
            set
            {
              if (value > 180) value -= 360;
              if (value < -180) value += 360;
              if (Math.Abs(heading - value) > 0.05)
              {
                heading = value;
                RaisePropertyChanged(() => Heading);
              }
            }
          }

          The map seems to try to keep its heading between 0 and 360 degrees, but I like to have the slider in the middle for North position – that way you can use it to rotate the map left and right. So I want heading to be between –180 and +180, which should be functionally equivalent to between 0 and 360 - and apparently I get away with it. Since both values are doubles I don’t do the standard equals but use a threshold value to fire a PropertyChanged. Courtesy of ReSharper suggesting this.

          Then there’s a MapCenter property, that doesn’t do very much in this solution apart from setting the initial map center. I have discovered that the center map does not like being set to null either – this beasty is a bit more picky than the Bing Maps control it seems so I take care to set an initial value:

          private GeoCoordinate mapCenter = new GeoCoordinate(40.712923, -74.013292);
          /// 
          /// Stores the map center
          /// 
          public GeoCoordinate MapCenter
          {
            get { return mapCenter; }
            set
            {
              if (mapCenter != value)
              {
                mapCenter = value;
                RaisePropertyChanged(() => MapCenter);
              }
            }
          }
          private double zoomLevel = 15;
          
          public double ZoomLevel
          {
            get { return zoomLevel; }
            set
            {
              if (zoomLevel != value)
              {
                zoomLevel = value;
                RaisePropertyChanged(() => ZoomLevel);
              }
            }
          }

          Together with the initial ZoomLevel set to 15, this will give you a nice view of Manhattan Island, New York City, USA. There's also a boolean property "Landmarks" that will enable or disable landmarks - you can look that up in the sources if you like.

          Then I opened up Blend, plonked in a map, two sliders, a checkbox on the screen, did some fiddling with grids and stuff, and deleted a lot of auto-generated comments. That made me end up with quite a bit of XAML. I won’t show it all verbatim, but the most important thing is the map itself:

          <maps:Map x:Name="map" 
                    CartographicMode="{Binding SelectedMode.CartographicMode,Mode=TwoWay}"
                    LandmarksEnabled="{Binding Landmarks,Mode=TwoWay}"
                    Pitch="{Binding Pitch, Mode=TwoWay}"
                    Heading="{Binding Heading, Mode=TwoWay}" 
                    Center="{Binding MapCenter, Mode=TwoWay}"
                    ZoomLevel="{Binding ZoomLevel, Mode=TwoWay}"
                    Grid.ColumnSpan="2"/>

          Does not look like exactly rocket science, right? It is not, as long as you make sure the maps namespace is declared as:

          xmlns:maps="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps" 

          The horizontal slider, controlling the heading, is defined as follows:

          <Slider Minimum ="-180" Maximum="180" Value="{Binding Heading, Mode=TwoWay}"/>
          The vertical slider, controlling the pitch, looks like this:
          <Slider Minimum="0" Maximum="75" Value="{Binding Pitch, Mode=TwoWay}" />

          Sue me, I took the easy way out and declared the valid ranges in XAML in stead of in my (view) model. But the point of the latter is this: apparently you can only supply ranges between 0 and 75 for pitch. And the pitch is only effective from about level 7 and higher. If you zoom out further, the map just become orthogonal (i.e. viewed straight from above, as if the pitch is 0). This is actually animated if you zoom out using pinch zoom, a very nice visual effect.

          Finally, the list picker controlling which kind of map you see, and the checkbox indicating if the map should show landmarks or not

          <toolkit:ListPicker ItemsSource="{Binding Modes}" 
                              SelectedItem="{Binding SelectedMode, Mode=TwoWay}" 
                              DisplayMemberPath="Name"/>
          <CheckBox Content="Landmarks" IsChecked="{Binding Landmarks, Mode=TwoWay}"/>

          … only I haven’t been able to find any landmarks, not in my hometown Amersfoort, not Berlin nor New York so I suppose this is something that’s not implemented yet ;-)

          CapMapIf you fire up this application you will get an immediate error message indicating that you have asked for the map but that you have not selected the right capability for this in the manifest. So double click on “Properties/WMAppManifest.xml” and select ID_CAP_MAP (yeah, the manifest’s got a nice editor too now), and fire up your app.

          And that’s all there is to your first spin with the new Windows Phone map control. It supports data binding – to an extent, and it’s easy to control and embed. Play with the sliders and scroll over the map – it’s amazingly fast and I can assure you it is even more so on actual hardware. Stay tuned: more is coming on this subject!

          Note: I have not touched upon creating and adding map keys to the map in this solution. This procedure is described here.

          As usual: download the sample solution here.

          03 October 2012

          A WinRT behavior to start a storyboard on an event

          Sometimes I get a bit distracted. In this article I mention a behavior that I wrote which starts a storyboard on an event, I even put in in the win8nl library – and then totally forget to blog about it, or even to announce it. So anyway, when Danny van Neyghem asked me about a problem that was almost solved by my behavior, I kinda remembered it, and that I totally forgot about it - and decided a) to improve it and b) to talk about it (well, write).

          World, meet StartStoryboardBehavior. It’s a very simple behavior that has the following properties:

          Storyboard The name of the Storyboard to start. Mandatory.
          StartImmediately true = don’t wait for an event to start, just start the storyboard when the behavior is loaded. Optional; default is false
          EventName The event of the AttachedObject that will initiate the start of the storyboard (e.g. ‘Click’ on a button). Ignored when StartImmediately  == true, mandatory otherwise
          SearchTopDown Optional, default is true. If true, the behavior will start to search for your storyboard from the top of the visual tree. This is the scenario in which for instance clicking a button will initiate a storyboard that sits somewhere in the top of the page. If this value is set to false, the behavior will search from the attached object up. Choose this setting when you use the behavior to start a storyboard that’s sitting inside a template.

          “SearchTopDown” was added just yet, and I hope it solves Danny’s problem. For those who just want to use the behavior: Nuget Win8nl and you have the behavior armed and ready. I’ve updated the package with the improved behavior already. For those who want to learn – well, it’s not rocket science but read on.

          The first part is not so very interesting – just your basic setting up of the behavior, the wiring up and a wiring down of the events. The only interesting things happen in AssociatedObjectLoaded:

          using System;
          using System.Linq;
          using Windows.UI.Xaml;
          using WinRtBehaviors;
          using System.Reflection;
          using Win8nl.External;
          using Windows.UI.Xaml.Media.Animation;
          using System.Reactive.Linq;
          
          namespace Win8nl.Behaviors
          {
            public class StartStoryboardBehavior : Behavior<FrameworkElement>
            {
              protected override void OnAttached()
              {
                base.OnAttached();
                AssociatedObject.Loaded += AssociatedObjectLoaded;
              }
              
              protected override void OnDetaching()
              {
                AssociatedObject.Loaded -= AssociatedObjectLoaded;
                base.OnDetaching();
              }
          
              private void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
              {
                if (StartImmediately)
                {
                  StartStoryboard();
                }
          
                if (!string.IsNullOrWhiteSpace(EventName))
                {
                  var evt = AssociatedObject.GetType().GetRuntimeEvent(EventName);
                  if (evt != null)
                  {
                    Observable.FromEventPattern<RoutedEventArgs>(AssociatedObject, EventName)
                      .Subscribe(se => StartStoryboard());
                  }
                }
              }
            }
          }

          If StartImmediately is true, the storyboard is fired immediately. If not, the behavior tries to find an event with the name supplied in the EventName property and tries to attach a dynamic handler to it using Rx. Nothing new here, I already described this technique earlier - in the article where I announced this forgotten behavior :-)

          More interesting is this funny little method, that’s basically one big Linq statement:

          private Storyboard GetStoryBoardInVisualDescendents(FrameworkElement f)
          {
            return f.GetVisualDescendents()
              .Where(p => p.Resources.ContainsKey(Storyboard) && p.Resources[Storyboard] is Storyboard)
              .Select(p => p.Resources[Storyboard] as Storyboard).FirstOrDefault();
          }

          It checks in all visual children’s resources for a storyboard with the name supplied in “Storyboard”, and if so, it selects it. It uses the extension method GetVisualDescendents to generate a list of all the children – all the way to the bottom of the visual tree from the element in “f”.

          As for the behavior’s default behavior (meh), it searches top-down for the storyboard, using this method:

          private void StartStoryboardTopDown()
          {
            var root = AssociatedObject.GetVisualAncestors().Last() ?? AssociatedObject;
          
            var storyboard = GetStoryBoardInVisualDescendents(root);
            if (storyboard != null)
            {
              storyboard.Begin();
            }
          }

          In a nutshell: find the very last top object in the visual tree – that is the root. If that’s null, apparently the current associated object already is the root. Then it starts to search downward for the storyboard and if it finds it, it will fire it.

          For the bottom-up strategy, another method is employed, with a very original name:

          private void StartStoryboardBottomUp()
          {
            var root = AssociatedObject;
            Storyboard storyboard;
            do
            {
              storyboard = GetStoryBoardInVisualDescendents(root);
              if (storyboard == null)
              {
                root = root.GetVisualParent();
              }
            } while (root != null && storyboard == null);
          
            if (storyboard != null)
            {
              storyboard.Begin();
            }
          }

          This method starts by trying to find the storyboard in the visual tree below the current associated object. If it doesn’t find it, in moves one level up and tries again. And another one. Till it a) finds the storyboard or b) runs out of levels. If a storyboard is found, then it fires it. Okay, so that’s a little inefficient, but it only happens upon firing the event.

          The final pieces of the puzzle is StartStoryboard, which simply selects the method based upon the SearchTopDown value.

          private void StartStoryboard()
          {
            if( SearchTopDown)
            {
              StartStoryboardTopDown();
            }
            else
            {
              StartStoryboardBottomUp();
            }
          }

          And that’s all there is to it. I’ve omitted the declaration of the four (attached dependency) properties as that only bulks up this post with no actual value, and the complete listing can be found here on CodePlex if that helps you to get overview.

          Screenshot8For those who love to see the behavior in action I created a little sample app, which shows a few items in a ListBox. At the end of each row there’s a button, and if you click that the color of three texts to the left is animated from black to red in about a second. That’s a storyboard being fired by the behavior. Very exiting ;-) - but it proves the point.

          Enjoy! I hope this helps you with your Windows 8 development! Global Availability is coming, get cracking to get your stuff in the store!