30 October 2012

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!

30 September 2012

Repairing the Windows Phone 7 behavior to show an image background for a search string

On the last day of 2011 ago I made DynamicBackgroundBehavior - a quite bizarre behavior which plays a supporting role in my latest Windows Phone application “What’s cooking”. It basically shows a picture from a search string as a background, using Bing Image search. Quite neat. Until Microsoft decided to change the Bing Search API a bit. Up until then, it had been a free unlimited ride – since about August you have to buy a package of searches (anything below 5000 searches per month is free). And some more stuff has been changed.

Microsoft provides a nice little C# client library that should solve all of this using an OData protocol. The sad thing is that for the life of it I could not get it to compile on Windows Phone. So I ended up analyzing the PHP (*shudder*) sample in this document – a Word document no less – to see what I needed to do (see page 27 and further).

From a coding perspective, the following details have been changed:

Okay. My cheese moved a little. First things first. I need base64 encoded text. Samples of this are on the internet a dime a dozen, I took this one:

/// <summary>
/// Converts string to base64
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
private string Base64Encode(string data)
{
  try
  {
    var encData_byte = new byte[data.Length];
    encData_byte = System.Text.Encoding.UTF8.GetBytes(data);
    return Convert.ToBase64String(encData_byte);
  }
  catch (Exception e)
  {
    throw new Exception("Error in Base64Encode" + e.Message);
  }
}

Now the method that does the actual calling of the Bing Search API has changed a little, but not very much:

/// <summary>
/// Start the image request using Bing Serach
/// </summary>
/// <param name="searchString"></param>
protected void StartGetFirstImage(string searchString)
{
  if (!string.IsNullOrWhiteSpace(searchString))
  {
    var queryUri =
      string.Format(
        "https://api.datamarket.azure.com/Data.ashx/Bing/Search/v1/Image?Query=%27{0}%27&$top=1&$format=Atom",
         HttpUtility.UrlEncode(searchString));
    var request = WebRequest.Create(queryUri) as HttpWebRequest;
    request.Headers["Authorization"] = "Basic " + Base64Encode(string.Format("{0}:{0}", BingSearchKey));
    
    var response =
      Observable.FromAsyncPattern<WebResponse>(
        request.BeginGetResponse, request.EndGetResponse)();
    response.Subscribe(WebClientOpenReadCompleted, WebClientOpenReadError);
  }
}

Note the new url. It goes to a different location, the search term must be enclosed by %27 (i.e. the double quote “) and I have to specify a format (Atom). Really interesting is the thing I marked red, for a variety of reasons:

  • Windows Phone’s Response.Headers collection does not sport the Add method. That stopped me a little, until I realized you could poke directly a new key in the collection by using [“Autorization”] =.
  • Now the authentication is Basic, followed by a space, your account key, colon, your key again and that key:key sequence needs to base 64 encoded. Why this is implemented this way – no idea, but it gets your key across – and validated.

The final thing is that in the callback WebClientOpenReadCompleted I need to use “http://schemas.microsoft.com/ado/2007/08/dataservices” for a namespace,as I already stated.

And then my little Windows Phone behavior works again. The fixed version can be downloaded here. I will fix my #wp7nl library on codeplex ASAP.

26 September 2012

Data binding shapes to the WinRT Bing Maps control – coming from Windows Phone

Disclaimer: this is not a 101 article. It requires understanding of the basic idea about MVVM, data binding, the MVVMLight messenger, and the use of behavior in Windows 8 XAML.

Updated for RTM Bing Maps Control October 3 2012

MVVMLightwp7

Introduction
Let me get this straight: I don’t want you to wean off Windows Phone development – far from it. It’s value proposition is great, and it will become much greater still. This article is yet another way to show you how to carry over code and architecture principles between Microsoft’s great tile based operating systems. It’s all about re-using skills and code. C# and XAML code that is.

Those who have attended my talks about this subject during this year, have seen the application to the right popping up. Basically it generates shapes (be it points, lines or polygons) by data binding from ‘business objects’ - using MVVMLight view models. If you tap any of those shapes, a “SelectCommand” on the bound view model will be fired, and the view model will put itself on the MVVMLight Messenger. Some other view model will listen for those messages, and pop up the info window. The app shows gas stations (points), roadblocks (lines) and buildings (shapes). Don’t go look for the gas stations, they are not there and the fuel prices a way bit behind the (expensive) times, the roadblock are all but one fictional as well. Only the buildings are real – location wise that is. Sources of the original Windows Phone (7) application can be found here:

Windows Phone map binding recap
A quick recap: if you want to data bind to a Bing Maps control in Windows Phone, you will go about like this – first, you would define a data template for a layer:

<DataTemplate x:Key="RoadBlockViewModelTemplate">
  <Microsoft_Phone_Controls_Maps:MapPolyline Locations="{Binding Geometry}"
                         Stroke="#FF71FF00"
                         StrokeThickness="5">
    <i:Interaction.Triggers>
      <i:EventTrigger EventName="Tap">
        <GalaSoft_MvvmLight_Command:EventToCommand 
             Command="{Binding SelectCommand}" />
      </i:EventTrigger>
    </i:Interaction.Triggers>
  </Microsoft_Phone_Controls_Maps:MapPolyline>
</DataTemplate>
This would be able to make a line geometry from a viewmodel containing a “Geometry” attribute containing a LocationCollection object, and an ICommand “SelectCommand” that is executed when the user taps the line. Second, you would make a Bing Maps control, and define a layer like this.
<Microsoft_Phone_Controls_Maps:Map x:Name="map"
    CredentialsProvider="Your-credentials-here">
  <Microsoft_Phone_Controls_Maps:MapLayer 
     x:Name="MapLayer_RoadBlocks">
    <Microsoft_Phone_Controls_Maps:MapItemsControl 
      ItemsSource="{Binding RoadBlocks}" 
      ItemTemplate="{StaticResource RoadBlockViewModelTemplate}"/>
  </Microsoft_Phone_Controls_Maps:MapLayer>
</Microsoft_Phone_Controls_Maps:Map>;

The roadblock view model would look like this:

using System.Windows.Input;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using Microsoft.Phone.Controls.Maps;
using MvvmMaps.Logic.Models.GeoObjects;
using MvvmMaps.Logic.Models.Geometries;
using Wp7nl.Utilities;

namespace MvvmMaps.Logic.ViewModels
{
  public class RoadBlockViewModel : ViewModelBase
  {
    public RoadBlock Model { get; set; }

    // Some code omitted
[DoNotSerialize] public LocationCollection Geometry { get { var modelGeom = Model.Location as LineGeometry; return modelGeom.GetLocationCollection(); } set { var modelGeom = Model.Location as LineGeometry; modelGeom.SetLocationCollection(value); } } [DoNotSerialize] public ICommand SelectCommand { get { return new RelayCommand( () => Messenger.Default.Send(this), () => true); } } } }

Basically it comes down to a Geometry view model property that converts a business object geometry to and from something the Bing Maps control understands – a LocationCollection. This is a named collection that contains objects of type GeoCoordinate – your basic Lat/Lon container. As said above, when you tap select the MVVMLight Messenger just sets off the selected viewmodel, and ‘something’  should capture that message and handle it.

Going to Windows 8 – challenges
Now let’s re-use our skills on Windows 8. Simply put – in its current state, the data binding support for the Bing Maps SDK for Windows Store apps is pretty easy to describe with one word – non-existent. Some developers immediately go into the ‘blame-and-flame-the-Microsoft-dev-team’ mode when they encounter things like this. I think ‘CodePlex library’. I always see things like this as an intellectual challenge, a chance to contribute to the community, and fortunately there are more people thinking that way. My very smart fellow Dutch developer community member Dave Smits has created BindableRTMaps, which is very useful for binding point objects – but its shape support is a bit limited. Being a GIS professional and an MVVMLight junkie, I want the control to be able to generate geographical elements directly from view models, just like I was able to do in Windows Phone. I solved the data binding issue for shapes using a Behavior based upon my WinRtBehaviors library. Not quite surprising for those who know me.

The result can be seen below:

Screenshot (9)

In the center, next to the river, the Vicrea offices, where I work. Say cheese fellows! ;-) As you can see, the shapes are beautifully re-projected when Birds’ Eye View is selected. This is the stuff that makes a GIS buff tick.

Researching the control I quickly found the following:

  • There’s no data binding support at all (as stated)
  • 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 MapShape, which in turn descends from DependencyObject – which is very fortunate, as I hope will become clear over the course of this article.

So I had the challenge to create something that can be put into XAML to still give the designer an amount of control how things appear, without having to resort to code.

Introducing MapShapeDrawBehavior 
The behavior I created is called MapShapeDrawBehavior  (I’ve never been one for original catchy names) and can be used like this:

<Maps:Map Credentials="Your-credentials-here">
  <WinRtBehaviors:Interaction.Behaviors>
  
    <MapBinding:MapShapeDrawBehavior 
       LayerName="Roadblocks" 
       ItemsSource="{Binding RoadBlocks, Mode=TwoWay}" 
       TapCommand="SelectCommand" PathPropertyName="Geometry" >
         <MapBinding:MapShapeDrawBehavior.ShapeDrawer>
           <MapBinding:MapPolylineDrawer Color="Green" Width="10"/>
         </MapBinding:MapShapeDrawBehavior.ShapeDrawer>
    </MapBinding:MapShapeDrawBehavior>
  
  </WinRtBehaviors:Interaction.Behaviors>
</Maps:Map>

For every category of objects there’s a layer – which translates to one behavior per list of objects, in this case the road blocks (the green line on the app sceenshot above). Then you need to define three things per layer:

  • What command in the item view model (in this case, a RoadBlockViewModel) must be fired when a MapShape’s only event – Tap – is called.
  • Which property in the item view model contains the Path – this is the terminology for a MapShape’s collection of points. This is, once again, of type LocationCollection. Only that’s no longer a collection of GeoCoordinate but of Location.
  • Finally, you need to define a drawer. A drawer is a concept I sucked from my own thumb – it determines how a collection of points is supposed to be transformed to something on the map. It’s my way to make something that’s not templatable more or less configurable.

I created three drawers out of the box: 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 MapShape CreateShape(object viewModel, LocationCollection path)

The basic drawers don’t do anything with the view model: they just take the settings from XAML. But if you want for instance your shapes having different colors based upon some view model property – say you want to color urban areas based upon their crime rate (what we GIS buffs call a thematic map) – you can write a little custom drawer.

If you just want to use the behavior you are done with reading. You can download the demo solution with code (which, incidentally, shows off a lot of more things than just binding to a map) and start playing around with it. Be aware of the following issues/caveats:

  • You will need to install the Bing Maps SDK for Windows Store apps first
  • When I moved the solution from my Big Black Box to my slate I had to delete and redo all references to Bing.Maps and “Bing Maps for C#, C++, or Visual Basic” (this was using the Beta, I don’t know if that still applies to the RTM version)
  • The control apparently contains native code, so you cannot build it for Any CPU.
  • The designer only works when you build for x86 (this still the case in RTM)

For the technically interested I will continue with some gory details.

The inner guts
The behavior itself is actually pretty big, so I won’t repeat all code verbatim; I will concentrate on the interesting parts.

First of all, I already mentioned the fact MapShape descends from DependencyObject. That spells ‘Ahoy, Attached Dependency Property ahead!’  to me. So I created two of those, one holding the name of the layer (I use those to find out which shapes belong to a single layer) and one in which I store the view model from which the shape was created:

using Windows.UI.Xaml;

namespace Win8nl.MapBinding
{
  public static class MapElementProperties
  {
    public static readonly DependencyProperty ViewModelProperty =
         DependencyProperty.RegisterAttached("ViewModel",
         typeof(object),
         typeof(MapElementProperties),
         new PropertyMetadata(default(object)));

    // Called when Property is retrieved
    public static object GetViewModel(DependencyObject obj)
    {
      return obj.GetValue(ViewModelProperty) as object;
    }

    // Called when Property is set
    public static void SetViewModel(
       DependencyObject obj,
       object value)
    {
      obj.SetValue(ViewModelProperty, value);
    }

    public static readonly DependencyProperty LayerNameProperty =
         DependencyProperty.RegisterAttached("LayerName",
         typeof(string),
         typeof(MapElementProperties),
         new PropertyMetadata(default(string)));

    // Called when Property is retrieved
    public static string GetLayerName(DependencyObject obj)
    {
      return obj.GetValue(LayerNameProperty) as string;
    }

    // Called when Property is set
    public static void SetLayerName(
       DependencyObject obj,
       string value)
    {
      obj.SetValue(LayerNameProperty, value);
    }
  }
}

The core of the MapShapeDrawBehavior self consists out of just five little methods, and the VERY core method is CreateShape. The behavior iterates over the object list databound to ItemsSource, and calls CreateShape for every view model:

/// <summary>
/// Creates a new shape
/// </summary>
/// <param name="viewModel"></param>
/// <returns></returns>
private MapShape CreateShape(object viewModel)
{
  var path = GetPathValue(viewModel);
  if (path != null && path.Any())
  {
    var newShape = CreateDrawable(viewModel, path);
    newShape.Tapped += ShapeTapped;

    MapElementProperties.SetViewModel(newShape, viewModel);
    MapElementProperties.SetLayerName(newShape, LayerName);

    // Listen to property changed event of geometry property to check 
    // if the shape needs tobe redrawed
    var evt = viewModel.GetType().GetRuntimeEvent("PropertyChanged");
    if (evt != null)
    {
      Observable
        .FromEventPattern<PropertyChangedEventArgs>(viewModel, "PropertyChanged")
        .Subscribe(se =>
                     {
                       if (se.EventArgs.PropertyName == PathPropertyName)
                       {
                         ReplaceShape(se.Sender);
                       }
                     });
    }
    return newShape;
  }
  return null;
}
  • First, it reads the view model property that holds the geometry (or at least, it tries that)
  • It creates the actual shape
  • It attaches an event listener to the “Tapped” event
  • It puts the view model and the layer name in attached dependency properties for said shape
  • Finally it attaches a property changed listener so that when the property that’s holding the view model’s geometry changes, the ReplaceShape method is called (which replaces the shape on the map – duh)

GetPathValue is a simple method that retrieves the view model’s geometry using reflection. Nothing special there:

private LocationCollection GetPathValue(object viewModel)
{
  if (viewModel != null)
  {
    var dcType = viewModel.GetType();

    var methodInfo = dcType.GetRuntimeMethod("get_" + PathPropertyName, 
                     new Type[0]);
    if (methodInfo != null)
    {
      return methodInfo.Invoke(viewModel, null) as LocationCollection;
    }
  }
  return null;
}

CreateDrawable – well that’s VERY simple. Get the drawer and let it decide how the shape will look

protected virtual MapShape CreateDrawable(object viewModel, LocationCollection path )
{
  var newShape = ShapeDrawer.CreateShape(viewModel, path);
  return newShape;
}

And finally ShapeTapped and FireViewModelCommand:

private void ShapeTapped(object sender, TappedRoutedEventArgs e)
{
  var shape = sender as MapShape;
  if( shape != null )
  {
    var viewModel = MapElementProperties.GetViewModel(shape);
    if( viewModel != null )
    {
      FireViewmodelCommand(viewModel, TapCommand);
    }
  }
}

private void FireViewmodelCommand(object viewModel, string commandName)
{
  if (viewModel != null && !string.IsNullOrWhiteSpace(commandName))
  {
    var dcType = viewModel.GetType();
    var commandGetter = dcType.GetRuntimeMethod("get_" + commandName, new Type[0]);
    if (commandGetter != null)
    {
      var command = commandGetter.Invoke(viewModel, null) as ICommand;
      if (command != null)
      {
        command.Execute(viewModel);
      }
    }
  }
}

ShapeTapped checks if it the object sending the event is actually a shape, then tries to retrieve a view model from the attached dependency property, and calls FireViewModelCommand on it. Which basically is directly ripped from my earlier EventToCommandBehavior. And then the circle is round again – user taps, view model command is called (just as Laurent Bugnion’s EventToCommand trigger did for Windows Phone) and the view model takes it further just like before.

There’s more to this behavior, but mostly it’s just reacting to events that occur when the ObservableCollection ItemsSource changes.

Some concluding remarks
Of course this behavior was geared to make the code I already had as much reusable as possible, but I think the way WinRT XAML apps and Windows Phone apps can be put together are remarkably similar – provided you make good use of MVVM and keep your code as clean as possible. So what did I have to do to move over my business and view model code to get this working? Well not very much, actually.

  • A tiny thing in my model library because I was so clever to use a BackgroundWorker somewhere in my models – which is not supported in WinRt
  • The Gas station view model was changed to do the conversion form business object geometry to Bing Maps’ Location in stead of the converter I originally - because my solution does not support converters.
  • I had to change some name spaces and data types. Mainly GeoCoordinate was now called Location.
  • Oh yeah – in stead of "clr-namespace" I had to use "using" for declaring namespaces in XAML. I used ReSharper toalt-enter trough the errors and add the namespaces almost automatically.

And that was about it. Of course, the code in it was quite trivial, but still. On the XAML side things were a bit more complicated:

  • Converters and Attached Dependency Properties were carried over with minimal changes.
  • I had to trash my geometry templates and had to write the behavior to emulate the templates – in a way, which admittedly was no small feat. But that’s a hole that only needs to be plugged once, and can now act as a base for possible better solutions.
  • I had to do some fiddling around with the DataTemplateSelector – that works a wee bit different, and will be subject of a future blog post.
  • ‘Tombstoning’ works a bit differently, but quite analogous. Been there, done that, wrote the blogpost.
  • The App Bar on Windows 8 has a lot more possibilities. And – thank Saint Sinofsky and his minions – it supports data binding out of the box. Moving from Windows Phone app bars to Windows 8 app bars is quite easy. Provided you used the BindableApplicationbar and MVVM of course ;-) 
  • I kinda 1:1 copied the data window (the popup with alphanumeric data that appears when you tap a shape) – that worked remarkably well, but you might want to do something about the styling for a real-world application. The data window is a wee bit small now and does fit in styling wise ;-)

This is still a work in progress, but I think for basic shape data binding this is already very usable. The Bing Maps control is very fast, courtesy of native code, no doubt. I hope this will help people.

Once again, for those who don’t feel scrolling all the way up: the source code. Also updated for RTM. Enjoy!

10 August 2012

A WinRT behavior to turn a FlipView into a kind of Windows 8 Panorama

IC425813(UPDATED for RTM August 18 2012)
One of the most beautiful controls of Windows Phone is the Panorama. It’s ideal for showing a lot related content on a small screen and enable the user to easily pan trough it. A visual cue for ‘there is more’ is provided by showing a little part of the next panel to the very right of the current data. A typical example is showed right.

It’s also one of the most abused controls (guilty as charged Your Honor), but still I wanted to port Catch’em Birds to Windows 8 – and I found out there was no ready-to-use control. After fighting with ScrollViewers and GridViewers and whatnot I came to this very simple behavior, which basically takes a FlipView and hammers it into a kind of Panorama.

Now the FlipView is designed to be a full-screen control so the behavior basically walks past all the items in the FlipView, shrinks them horizontally by a configurable percentage of the screen, and displaces the ‘next’ panel a little to the left (making it appear at the right side of the screen on the current panel). To make this look a little bit more fast and fluid, I have made the displacement itself animated, so that the ‘next’ screen not so much snaps as glides into view. The overall effect looks pretty nice to me. I hope Microsoft will think so as well, as my app is up for an App Excellence Lab soon ;-)
In my app it looks like this. I still lack a decent screen recorder for Windows 8, so I took out the video camera

So this behavior, most originally called “FlipViewPanoramaBehavior” is of course based upon my earlier WinRtBehaviors CodePlex project. It starts out like this, with the following dependency properties:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Win8nl.External;
using Win8nl.Utilities;
using WinRtBehaviors;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;

namespace Win8nl.Behaviors
{
  /// <summary>
  /// A behavior to turn a FlipView into a kind of panorama
  /// </summary>
  public class FlipViewPanoramaBehavior : Behavior<FlipView>
  {
    #region AnimationTime

    /// <summary>
    /// AnimationTime Property name
    /// </summary>
    public const string AnimationTimePropertyName = "AnimationTime";

    public int AnimationTime
    {
      get { return (int)GetValue(AnimationTimeProperty); }
      set { SetValue(AnimationTimeProperty, value); }
    }

    /// <summary>
    /// AnimationTime Property definition
    /// </summary>
    public static readonly DependencyProperty AnimationTimeProperty = 
      DependencyProperty.Register(
        AnimationTimePropertyName,
        typeof(int),
        typeof(FlipViewPanoramaBehavior),
        new PropertyMetadata(250));

    #endregion

    #region NextPanelScreenPercentage

    /// <summary>
    /// NextPanelScreenPercentage Property name
    /// </summary>
    public const string NextPanelScreenPercentagePropertyName = 
      "NextPanelScreenPercentage";

    public double NextPanelScreenPercentage
    {
      get { return (double)GetValue(NextPanelScreenPercentageProperty); }
      set { SetValue(NextPanelScreenPercentageProperty, value); }
    }

    /// <summary>
    /// NextPanelScreenPercentage Property definition
    /// </summary>
    public static readonly DependencyProperty NextPanelScreenPercentageProperty = 
      DependencyProperty.Register(
        NextPanelScreenPercentagePropertyName,
        typeof(double),
        typeof(FlipViewPanoramaBehavior),
        new PropertyMetadata(10.0));
    #endregion
  }
}
So “AnimationTime” is the number of milliseconds the behavior takes to glide the next panel into view, and NextPanelScreenPercentage is an indication of how much screen real estate the next panel will take. Nothing special here yet.

If I want to muck around with a FlipView contents, I first have to find these contents. With some breakpoints and watches I found out I could use the following code to find the FlipViewItems:
/// <summary>
/// Find all Flip view items
/// </summary>
/// <returns></returns>
private List<FlipViewItem> GetFlipViewItems()
{
  var grid = AssociatedObject.GetVisualChildren().FirstOrDefault();
  if (grid != null)
  {
    return grid.GetVisualDescendents().OfType<FlipViewItem>().ToList();
  }
  return null;
}
Attentive readers might observe that neither GetVisualChildren nor GetVisualDescendents are part of the WinRT api, which is perfectly correct – they come from the VisualTreeHelperExtensions I ported from Windows Phone some time ago. Don’t start to download this stuff and build it together yourself – wait till the end and I will show the lazy way to do this.

Anyway – I wanted to move the FlipView’s contents fluently. That means I will use some Storyboards to work on Translations. So we identify the contents of each FlipViewItem and set its fist visual child’s Rendertransform to CompositeTransform, if that’s not already present:
/// <summary>
/// At compositions transforms to every item within every flip view item
/// </summary>
private void AddTranslates()
{
  var items = GetFlipViewItems();
  if (items != null && items.Count > 1)
  {
    foreach (var item in items)
    {
      var firstChild = item.GetVisualChild(0);
      if (!(firstChild.RenderTransform is CompositeTransform))
      {
        firstChild.RenderTransform = new CompositeTransform();
        firstChild.RenderTransformOrigin = new Point(0.5, 0.5);
      }
    }
  }
}
This assumes every FlipViewItem contains just one child. You better make sure it does for this to work, so put a Grid around it if you need more than one thing to sit in there.

Now the core of the whole behavior is this one piece of code:
/// <summary>
/// Does the actual repositioning and sizing of the items displayed in the Flipview
/// </summary>
private void SizePosFlipViewItems()
{
  AddTranslates(); // <-- moved from AssociatedObjectLoaded for RTM
  var size = AssociatedObject.ActualWidth*(NextPanelScreenPercentage/100);
  var shift = size - 15;

  var items = GetFlipViewItems();
  if (items != null && items.Count > 1)
  {
    // Make all items a bit smaller and make sure they are aligned left
    foreach (var item in items)
    {
      item.GetVisualChild(0).HorizontalAlignment = HorizontalAlignment.Left;
      item.GetVisualChild(0).Width = items[0].ActualWidth - size;
    }

    var selectedIndex = AssociatedObject.SelectedIndex;

    if (selectedIndex > 0)
    {
      StartTranslateStoryBoard(0, 0, 
                               items[selectedIndex - 1].GetVisualChild(0), 0);
    }

    StartTranslateStoryBoard(0, 0, items[selectedIndex].GetVisualChild(0), 
                             AnimationTime);

    if (selectedIndex + 1 < items.Count)
    {
      StartTranslateStoryBoard(-shift, 0,
                                items[selectedIndex + 1].GetVisualChild(0), 
                                AnimationTime);
    }
  }
}
First it calculates the new size of the FlipViewItems, and then it calculates how much it can shift the ‘next panel’ – basically, how much room is there between this panel and the next. This is currently a hard coded number, but feel free to make that a property as well ;-).

Then, for every FlipViewItem it makes the first visual child “size” smaller, and makes sure it’s aligned to the left (so space comes free and the right side). Then:
  1. It moves the panel that just disappeared to the left (if any) back  to it’s normal position, in no time (i.e. not animated – it’s invisible to the leftanyway, so why bother).
  2. It moves the current panel to its normal position, but it animates it. This is because if it’s moved in from the left, it moves a bit too far, as you might have noticed in the movie – so it glides back
  3. It moves the next panel (if any) a little bit to the left – animated, so it glides into view on the right hand side of the screen.
Now of course there is the slight matter of the method that make the storyboards to make it happen:
private static void StartTranslateStoryBoard(double desiredX, double desiredY, 
                                             FrameworkElement fe, int time)
{
  var translatePoint = fe.GetTranslatePoint();
  var destinationPoint = new Point(desiredX, desiredY);
  if (destinationPoint.DistanceFrom(translatePoint) > 1)
  {
    var storyboard = new Storyboard { FillBehavior = FillBehavior.HoldEnd };
    storyboard.AddTranslationAnimation(
         fe, translatePoint, destinationPoint,
         new Duration(TimeSpan.FromMilliseconds(time)),
         new CubicEase { EasingMode = EasingMode.EaseOut });
    storyboard.Begin();
  }
}
Once again, I use some extension methods from code ported from Windows Phone in the article I mentioned before, I underlined them to make them distinguishable from the standard API. Basically: this method accepts a FrameworkElement and moves it to a desired position in a desired time, using a storyboard that animates a translation. That is to say, unless it is already in that desired position. I think I will make this into a separate extension method in a utilities library one day but for the moment it’s doing fine.

All that’s left now is some wiring up, I cobbled that all together in one code block:
protected override void OnAttached()
{
  AssociatedObject.Loaded += AssociatedObjectLoaded;
  base.OnAttached();
}
protected override void OnDetaching()
{
  AssociatedObject.Loaded -= AssociatedObjectLoaded;
  AssociatedObject.SelectionChanged -= AssociatedObjectSelectionChanged;
  AssociatedObject.SizeChanged -= AssociatedObjectSizeChanged;
}

private void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
{
  //AddTranslates(); deleted for RTM
  SizePosFlipViewItems();
  AssociatedObject.SelectionChanged += AssociatedObjectSelectionChanged;
  AssociatedObject.SizeChanged += AssociatedObjectSizeChanged;
}

private async void AssociatedObjectSelectionChanged(object sender, 
                                                    SelectionChangedEventArgs e)
{
  await Task.Delay(250); // Updated after bug report from SCPRedMage
  SizePosFlipViewItems();
}

private async void AssociatedObjectSizeChanged(object sender, 
                                               SizeChangedEventArgs e)
{
  await Task.Delay(250);
  SizePosFlipViewItems();
}
OnAttached and OnDetaching do their usual basic wiring and unwiring of events.
When the AssociatedObject (i.e. the FlipView) is first loaded the FlipViewItems’ first child gets their CompositeTransforms, then the initial screen layout is created by calling SizePosFlipViewItems. Then two events are wired up:
  • SelectionChanged
  • SizeChanged
Now the first one is logical – when the user selects the next panel (i.e. he scrolls it in from the left or right) the panels need to be arrange again so that the newly selected panel stays in view (it scrolls too much to the right, remember) and the ‘new’ next panel comes into view at the left hand side of the screen.

The SizeChanged intercept is necessary for when the user rotates his screen or snaps the application. For then the size of the screen changes, and the portion of the screen that the next panel may use is considerably smaller – in pixels. In my app this is taken care of by a Visual State Manager that listens to page events – basically something stolen from the LayoutAwarePage that’s in every template project – but that takes a while. Now I know I am going to be lambasted for this (and I have a pretty good idea by whom), but to solve this the SizeChanged handler waits a bit for actually calling SizePosFlipViewItems. And to prevent UI blocking I interestingly abused Task.Delay for that. It’s crude, but it works. As you may have seen in the movie when I snapped the app.

So there you have it. The code works, you have seen it in action. Its usage is ridicilously simple: make a FlipView, add items, and add this behavior to the FlipView. Done. You can download the the behavior here but you will need quite some base libs to get it working – as it uses a lot of my win8nl library on CodePlex. If you want to go the easy and quick way: just use the Win8nl NuGet package. That will get you the behavior and all the prerequisites, including MVVMLight.

Be aware that win8nl now uses the Reactive extensions. They are included in the NuGet package and they will come with it as a dependency

UPDATE: Please note there is a tiny code change since original publication: due to Microsoft optimizing the FlipView not all elements are initially loaded, so the check if every FlipViewItem child has a CompositeTransform has to performed at every manipulation.

UPDATE 2: There's a tiny update to AssociatedObjectSelectionChanged. And those who want a simple working sample, download the sources from codeplex and fire up FlipViewTest.XAML as the start page.

24 July 2012

A WinRT behavior to mimic EventToCommand

This is deprecated. Please use the official behaviors SDK now. See here for a simple migration guide

Updated September 2 2012 with two sample applications

Whoever used the MVVMLight framework by Laurent Bugnion is familiar with EventToCommand, especially those who used it on Windows Phone before the advent of 7.5 (or SDK version 7.1.1). This utility enables triggers to fire commands on the viewmodel

Unfortunately, in WinRT there is no such thing as a trigger, so this method cannot be used, and MVVMLight for WinRT therefore does not include EventToCommand. This morning I got a DM from AESIR Consultancy asking me if I had a solution for that, because he had some trouble porting a Windows Phone app to Windows 8. I did not have it then, but I had the feeling it could be done quite easily. In the afternoon, in the time between I came home and my wife came home from work I wrote this behavior that basically does the same as EventToCommand.

And indeed, WinRT does not support behaviors either, but that has been solved already. In order for this to work, you will need to download the NuGet WinRtBehaviors package

Anyway – the behavior. You start out with a project with references to WinRtBehaviors and the Reactive extensions – ReSharper 7 EAP found them readily and automatically attached references to my projects which now has the following references to reactive stuff:

  • System.Reactive.Core
  • System.Reactive.Interfaces
  • System.Reactive.Linq
  • System.Reactive.PlatformServices

So we start out with the class definition and some boring Dependency property definitions:

using System;
using System.Reactive.Linq;
using System.Reflection;
using System.Windows.Input;
using WinRtBehaviors;
using Windows.UI.Xaml;

namespace Win8nl.Behaviors
{
  /// <summary>
  /// A behavior to imitate an EventToCommand trigger
  /// </summary>
  public class EventToCommandBehavior : Behavior<FrameworkElement>
  {

    #region Event

    /// <summary>
    /// Event Property name
    /// </summary>
    public const string EventPropertyName = "Event";

    public string Event
    {
      get { return (string)GetValue(EventProperty); }
      set { SetValue(EventProperty, value); }
    }

    /// <summary>
    /// Event Property definition
    /// </summary>
    public static readonly DependencyProperty 
      EventProperty = DependencyProperty.Register(
        EventPropertyName,
        typeof(string),
        typeof(EventToCommandBehavior),
        new PropertyMetadata(default(string)));

    #endregion

    #region Command

    /// <summary>
    /// Command Property name
    /// </summary>
    public const string CommandPropertyName = "Command";

    public string Command
    {
      get { return (string)GetValue(CommandProperty); }
      set { SetValue(CommandProperty, value); }
    }

    /// <summary>
    /// Command Property definition
    /// </summary>
    public static readonly DependencyProperty 
      CommandProperty = DependencyProperty.Register(
        CommandPropertyName,
        typeof(string),
        typeof(EventToCommandBehavior),
        new PropertyMetadata(default(string)));

    #endregion

    #region CommandParameter

    /// <summary>
    /// CommandParameter Property name
    /// </summary>
    public const string CommandParameterPropertyName = "CommandParameter";

    public object CommandParameter
    {
      get { return (object)GetValue(CommandParameterProperty); }
      set { SetValue(CommandParameterProperty, value); }
    }

    /// <summary>
    /// CommandParameter Property definition
    /// </summary>
    public static readonly DependencyProperty 
        CommandParameterProperty = DependencyProperty.Register(
        CommandParameterPropertyName,
        typeof(object),
        typeof(EventToCommandBehavior),
        new PropertyMetadata(default(object)));

    #endregion
  }
}

All very boring, all very standard. Now, for dynamically adding a listener to the event: I’ve been down this road before, say hello to our friend Observable.FromEventPattern, which takes away all the boring details about the differences between ordinary and WinRT events.

protected override void OnAttached()
{
  var evt = AssociatedObject.GetType().GetRuntimeEvent(Event);
  if (evt != null)
  {
    Observable.FromEventPattern<RoutedEventArgs>(AssociatedObject, Event)
      .Subscribe(se => FireCommand());
  }
  base.OnAttached();
}

Nothing special. Try to find an event with the same name as the contents of the “Event” property and add a listener to it. And the final piece of the puzzle is the actual implementation of FireCommand. Of course, I could have implemented this inline but I like to make this a separate method, if only for readability:

private void FireCommand()
{
  var dataContext = AssociatedObject.DataContext;
  if (dataContext != null)
  {
    var dcType = dataContext.GetType();
    var commandGetter = dcType.GetRuntimeMethod("get_" + Command, new Type[0]);
    if (commandGetter != null)
    {
      var command = commandGetter.Invoke(dataContext, null) as ICommand;
      if (command != null)
      {
        command.Execute(CommandParameter);
      }
    }
  }
}

As always, when you know how to do it, it’s very simple. This method gets the AssociatedObject’s data context, the tries to find the getter of the Command property on this data context. As you might remember, a command in MVVMLight is defined like this:

public ICommand DoSomethingCommand
{
  get
  {
    return new RelayCommand<string>((p) =>
        {
          System.Diagnostics.Debug.WriteLine("Hi there {0}", p);
        });
  }
}

so I am not looking for a command method, but for a getter returning a command. If the code finds that, it tries to Invoke the getter as an ICommand. If it gets that it has the actual command, and it executes it. And that’s all!

So if you want to use this behavior, attach it to a Page’s main grid, for instance:

<Grid Style="{StaticResource LayoutRootStyle}" x:Name="TopView" x:Uid="TopGrid">
   <WinRtBehaviors:Interaction.Behaviors>
    <Win8nl_Behavior:EventToCommandBehavior Event="Tapped"
Command="DoSomethingCommand"
CommandParameter="John doe"/> </WinRtBehaviors:Interaction.Behaviors> <!--- stuff in here --> </Grid>

The top of your page needs to include this name space definitions:

xmlns:WinRtBehaviors="using:WinRtBehaviors"
xmlns:Win8nl_Behavior="using:Win8nl.Behaviors"

and then it will work. Tap on the main grid and you will see the text “Hi there John doe” in the Visual Studio output window. Of course you can make it do more useful things too ;-) and you can also bind things to the CommandParameter property using the normal binding syntax. To a certain extent.

You can download the behavior’s code here, but it's actually a lot easier to just use the NuGet Package. The behavior is there, along with some more nice stuff, and it takes care of downloading WinRtBehaviors and Reactive Extensions for WinRT as well

By special request I've also created sample code - not one but two solutions. The first one, TestWin8nl, is a very simple application that allows you to tap a TextBlock - this will trigger a command in the ViewModel that uses Debug.WriteLine to print a property of the ViewModel in your output console windows, using the CommandParameter to transfer the bound object (the ViewModel itself) to the command. The seconds sample, EventToCommandListDemo, will show you how to handle a SelectionChanged event of a ListBox, although frankly I'd rather just bind SelectedItem and act on it's property setter. But the audience asks, the audiences gets ;-). It appears tough as if Element name binding does not work properly in WinRtBehaviors, so I had to use a ViewModel property to store the selected item in anyway. Both are some contrived examples, but I hope the will do the trick of helping you out understanding how things are working and are supposed to be used.

Update: I have also blogged (and published in win8nl) a variant of the behavior that takes a bound command in stead of a command name. I personally now think this is a better solution as it adheres more to the way regular behaviors work, and is much more flexible Update 2: both this behavior and it's the bound-command-behavior are in the win8nl nuget package. Don't type, be lazy, use Nuget ;-)

23 July 2012

Using a provisional WinRT port of SilverlightSerializer to store state in MVVMLight ViewModels

Over 1.5 years ago I showed how to store your Windows Phone application state (‘tombstoning’) using SilverlightSerializer by Mike Talbot. In my quest to leverage hard-won Windows Phones skills to be usable in Windows 8 I made a provisional port of SilverlightSerializer 1 to WinRT. That is, in C#.

Since my win8nl library port is a bit behind, I’ve stuck the class in a simple project that you can download here.

Usage is as follows: in App.xaml.cs, you define two methods: SaveState and RestoreState:

private async void SaveState()
{
  var file = 
    await ApplicationData.Current.LocalFolder.CreateFileAsync(
      "AppState.dat", CreationCollisionOption.ReplaceExisting);

  using (var fileStream = await file.OpenStreamForWriteAsync())
  {
    SilverlightSerializer.Serialize(MainViewModel.Instance, fileStream);
  }
}

Pretty simple: when the state needs to be saved, create a file, get a stream, and let SilverlightSerializer do its magic. As for RestoreState:

private async Task RestoreState()
{
  try
  {
    var files = await ApplicationData.Current.LocalFolder.GetFilesAsync();
    var dataFile = files.FirstOrDefault(p => p.Name == "AppState.dat");
    if (dataFile != null)
    {
      using (var fileStream = await dataFile.OpenSequentialReadAsync())
      {
        MainViewModel.Instance = 
          SilverlightSerializer.Deserialize(fileStream.AsStreamForRead()) 
            as MainViewModel;
      }
    }
  }
  finally
  {
    if (MainViewModel.Instance == null) MainViewModel.CreateNew();
    MainViewModel.Instance.Start();
  }
}

This basically tries to deserialize a viewmodel from a file “AppState.dat”. If that fails, it creates a new MainViewModel, and starts it. The whole idea behind this is described in the original Windows Phone 7 post, so I encourage you to read that if you have no idea what I am doing here.

Now the important bit is when to call this methods. If you think the most logical place for RestoreState is in OnLaunched, you are right. The first few lines of my OnLaunced method in App.xaml.cs look like this in my app:

if (args.PreviousExecutionState == ApplicationExecutionState.Running)
{
  Window.Current.Activate();
  return;
}
else
{
  await RestoreState();
}

Now the most logical place to call SaveState is of course OnSuspending, and we are done, right?

Wrong.

To my own utter surprise, yesterday, after a long debugging session, I found a weird edge scenario. I asserted the following: if a user closes an app by the “Swipe Down gesture”, it takes about 10 seconds (on my Samsung Slate 7) before OnSuspending is called. When the user restarts the app within those 10 seconds from the start screen, the state is not stored yet, or too late – in any case it is not yet available to the (yet again) starting app. So you don’t get the last state, but the state before that, as I shamefully discovered when I proudly showed my state save method to an Application Excellence Lab Microsoftie :(

Don’t get me wrong – the actual time SaveState runs in my app is about 0.047 seconds. It’s lightning fast – just like the original SilverlightSerializer. But the time between user closing the app and the actual state save being fired up was killing my state.

The solution to this is very simple: when the user closes the app, Window.Current.VisibilityChanged is fired. Not like after a few seconds, but instantly. So add and event listener to that at the bottom of OnLaunched, that calls SaveState , like this:

 Window.Current.VisibilityChanged += (o, e) => {if (!e.Visible) SaveState();};

Basically: if the visibility of the current windows changes to invisible, write the state. Maybe you write app state too often (for example because the user temporarily puts it in the background, then VisibilityChanged is fired as well) but at least you circumvent the problem I ran into. Since state writing takes very little time, better often than not at all, I’d say.

And in OnSuspending? Well, you could call SaveState from there, too. That’s useful when your app does something in the background and it’s state changes even when the users has put it in the background. Then, when the OS kicks it into suspension because it runs out of memory, the state is saved too.

Caveat emptor: I kinda roughly hacked Mike Talbots work to operate in the WinRT world. The current state is ‘works for me’. I commented out the whole section about Dictionary support, so I suppose that does not work. My ultimate goal is to convert SilverlightSerializer 2, but that was too big a bone to chew in a short time. It serves my ported game Catch’em Birds fine. I hope to get it finished soon.