20 June 2012

Reflection in WinRT: use Rx Extensions for dynamically adding event handlers

Suppose you want to add an event handler, but you don’t know up front which event. Admittedly, this is a bit of an edge case, but I have used it in a behavior that starts a storyboard upon an event (I will publish that later). The designer can specify the event using a string value in XAML, so I cannot simply use object.MyEvent += (handler). We need reflection here.

So suppose you have found the event in the object using the GetRuntimeXXX methods like I described earlier today, and want to dynamically add a handler to the event “MyEvent”:

var evt = MyObject.GetType().GetRuntimeEvent("MyEvent");
evt.AddEventHandler(MyObject, 
  new EventHandler((p, q) => {// your code here }));

This will compile, and even run - unless the object is, for instance, a Grid, and the event “Loaded”. That’s apparently a “WinRT event”, whatever that may be, and this will result in a runtime exception:

"Adding or removing event handlers dynamically is not supported on WinRT events."

Googling Binging this message leads to all kind of complicated solutions using the WindowsRuntimeMarshall class (without any samples, alas), but the solution turns out to be very simple: use Rx Extensions Beta for Windows RT. For the really lazy reader: click tools/Library Package Manager/Package Manager Console and enter “Install-Package Rx-Main –Pre” in the Package Manager Console.

Now add

using System.Reactive.Linq;

to the top of the code file and then simply use the following code:

Observable.FromEventPattern<RoutedEventArgs>(MyObject, "MyEvent")
  .Subscribe(se => { // your code here });

and you are done. The difference between ordinary events and “WinRT events” is apparently swallowed up in the bowels of Rx. This library is great to begin with, but if it saves you the trouble of digging in yet another still not very thoroughly documented API, it’s even better. As a bonus, by very nature of Rx the handler is automatically disposed of when your calling object goes out of scope, which is not necessarily the case in my first code. But that did not work anyway ;-)

Reflection in WinRT: DeclaredProperties vs GetRuntimeProperties caveat

I suppose this is part of some FM I did not R, but I would like to point it out in case some other sod wastes just as much time on it as me.

I embarked upon a journey to port SilverlightSerializer and some behaviors to WinRT. All stuff is heavily making use of reflection. Now reflection has been hugely overhauled in WinRT, so I knew I was in for an interesting ride. Recently I was convinced I managed to do it, but it turned out I did not.

There are apparently two ways to use reflection in RT. What I did use for reading all properties of an object, was:

var properties = MyObject.GetType().GetTypeInfo().DeclaredProperties;

But it turns out this returns only the properties declared in the class itself. What it does not return, are the properties of possible parent classes!

What I should have used, apparently, is:

var allproperties = MyObject.GetType().GetRuntimeProperties();

When I feed a Grid into “MyObject”,  “properties” hold 6 properties, while “allproperties” holds 51.

I don’t know why this distinction is made, and I understand even less how come I missed this the first time. On my first meeting as an MVP, Dennis Vroegop, after welcoming me to the club, already warned me that the MVP award did not automatically come with super powers. Boy, was he right.

14 June 2012

NavigationService for WinRT

"If I have been able to see further than others, it is because I have stood on the shoulders of giants."
 Isaac Newton

It was only 1.5 years ago, but it seems already a long time ago that Laurent Bugnion described a “view service” for Windows Phone navigation, commonly know as the NavigationService. I’ve incorporated this code in my #wp7nl library on codeplex and have been using it happily ever since (and a lot of other people I know have been doing so as well), Time goes on, along came Windows 8 and WinRT and Metro Style Apps.

Laurent ported his MVVMLight framework to WinRT as well. But the NavigationService never has been a core part of MVVMLight (therefore I put it in the #wp7nl library) and porting it to WinRT as well proved to be a bit of a hassle. Some of its premises where no longer valid – most notable the way to retrieve the main application frame by accessing Application.Current.RootVisual, which does not work in WinRT. I messed around a little with the code, did not get anywhere, and left it there. So I was glad I saw my fellow Windows Phone Development MVP Matteo Pagani tweet he got a NavigationService to work. He was kind enough to mail me the code. He basically copied the code from Windows Phone and made the apps rootFrame, as created in the App.xaml.cs, publicly available. A neat trick, with as only drawback that you have to copy the code to every app. As things goes, it’s usually easier to see someone else’s idea and improve it, than think it up out of the blue. I toyed around with it and managed to get rid of the need to copy the code, so I could put it in a library.

And here it is, an improved version of a NavigationService for WinRT, based upon Matteo’s code based upon Laurent’s code ;-)

First of all, the NavigationService’s interface:

using System;
using Windows.UI.Xaml.Navigation;

namespace Win8nl.Services
{
  public interface INavigationService
  {
    event NavigatingCancelEventHandler Navigating;
    void Navigate(Type type);
    void Navigate(Type type, object parameter);
    void Navigate(string type);
    void Navigate(string type, object parameter);
    void GoBack();
  }
}

This quite looks like the old interface, with some notable exceptions. First of all, the NavigateTo method is renamed Navigate, to mimic the method name used in WinRT itself. And it has not one but four overloads. The first two are pretty logical – WinRT does not use an uri for navigation, but an actual Type object, making strongly-typed navigation possible. And it supports an overload for a parameter object, as well. The two other methods, with the string type object… well see for yourself below, in the implementation of the service:

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace Win8nl.Services
{
  public class NavigationService : INavigationService
  {
  public NavigationService(Frame mainFrame)
  {
    _mainFrame = mainFrame;
  }

  private Frame _mainFrame;
  
  public event NavigatingCancelEventHandler Navigating;

  public void Navigate(Type type)
  {
    _mainFrame.Navigate(type);
  }

  public void Navigate(Type type, object parameter)
  {
    _mainFrame.Navigate(type, parameter);
  }

  public void Navigate(string type, object parameter)
  {
    _mainFrame.Navigate(Type.GetType(type), parameter);
  }

  public void Navigate(string type)
  {
    _mainFrame.Navigate(Type.GetType(type));
  }

  public void GoBack()
  {
    if (_mainFrame.CanGoBack)
    {
      _mainFrame.GoBack();
    }
  }  
}

So the string type methods allow you to specify the page to navigate by string. Before you all think I really lost my marbles this time, re-introducing weakly typed navigation just as the Windows team introduced strongly typed: I specifically added this as to allow navigation to be initiated from a ViewModel contained in an assembly not containing the XAML code. This also enables you to test code as well. This is the way I built my solutions for Windows Phone, and I intend to go on this way in Windows 8. ;-)

Anyway, there’s a thing missing in this code: the EnsureMainFrame that looked up the root page, for which Matteo used a public property. I completely removed it, and added a constructor accepting that root page. By creating that constructor I deleted the default constructor, so registering the NavigationService at he SimpleIoc container shipped with MVVMLight in the App.xaml.cs, like this:

SimpleIoc.Default.Register<INavigationService, Wp7nl.Utilities.NavigationService>();

as we did in Windows Phone code, won’t work anymore. Fortunately, SimpleIoc also supports factory methods to create an instance. So now you go to the App.xaml.cs of your Windows 8 app, find the OnLaunched method and just behind this line:

var rootFrame = new Frame();

you add this piece of code:

SimpleIoc.Default.Register<INavigationService>(() => 
                                   {return new NavigationService(rootFrame);});

Now if your XAML code and ViewModels are all in one assembly, you can call the NavigationService to navigate to the main page this:

SimpleIoc.Default.GetInstance<INavigationService>().Navigate(typeof(MainPage));

or if you are a bit stubborn like me and would like to separate ViewModels and views, you can use the string overload to specify the full qualified name and for instance use it in a ViewModel command like this

public ICommand TestNavigatieCommand
{
   get
   {
     return new RelayCommand(() => 
       SimpleIoc.Default.GetInstance<INavigationService>().Navigate("MyApp.MainPage,MyApp"));
   }
}

And there you have, a fully functional NavigationService for Windows 8. Code can be downloaded here. I will soon incorporate it in the provisional port of the #wp7nl library called win8nl.

Thanks to Laurent and Matteo for being my trailblazers ;-)

Behavior to make Bing Maps view area bindable

The Bing Maps control in Windows Phone 7 is pretty versatile but does not always play along very well with data binding. You can bind ZoomLevel and MapCenter, which is all very well, but if you want to know what area is actually shown within the map – for instance, for making a GIS application that loads only visible data, and not stuff that’s outside the view area anyway, things get a lit complicated.

Not so if you uses this little behavior. It builds upon the SafeBehavior that is already in my wp7nl library on codeplex. It sports two GeoCoordinate depencency propertise, NorthEast and SouthWest

using System.Device.Location;
using System.Windows;
using Microsoft.Phone.Controls.Maps;

namespace Wp7nl.Behaviors
{
  public class ViewportAreaBehavior
  {
    /// <summary>
    /// A behavior to make southwest and northeast bindable
    /// </summary>
    public class ViewportwatcherBehavior : SafeBehavior<Map>
    {
      #region NorthWest
      public const string NorthWestPropertyName = "NorthWest";

      public GeoCoordinate NorthWest
      {
        get { return (GeoCoordinate)GetValue(NorthWestProperty); }
        set { SetValue(NorthWestProperty, value); }
      }

      public static readonly DependencyProperty NorthWestProperty = 
	DependencyProperty.Register(
          NorthWestPropertyName,
          typeof(GeoCoordinate),
          typeof(ViewportwatcherBehavior),
          new PropertyMetadata(null));

      #endregion

      #region SouthEast
      public const string SouthEastPropertyName = "SouthEast";

      public GeoCoordinate SouthEast
      {
        get { return (GeoCoordinate)GetValue(SouthEastProperty); }
        set { SetValue(SouthEastProperty, value); }
      }

      public static readonly DependencyProperty SouthEastProperty = 
	DependencyProperty.Register(
          SouthEastPropertyName,
          typeof(GeoCoordinate),
          typeof(ViewportwatcherBehavior),
          new PropertyMetadata(null));

      #endregion
    }
  }
}

All pretty standard stuff. Next comes the setup/cleanup stuff,

protected override void OnSetup()
{
  AssociatedObject.ViewChangeEnd += AssociatedObjectViewChangeEnd;
  CalcRectangle();
}

protected override void OnCleanup()
{
  AssociatedObject.ViewChangeEnd -= AssociatedObjectViewChangeEnd;
}

in which you can see I intercept the ViewChangeEnd event. I don’t do anything special there: I just call the method CalcRectangle, just as on startup.

void AssociatedObjectViewChangeEnd(object sender, MapEventArgs e)
{
  CalcRectangle();
}

The final missing piece of the puzzle is then of course CalcRectangle itself:

private void CalcRectangle()
{
  NorthWest = AssociatedObject.ViewportPointToLocation(new Point(0, 0));
  SouthEast = AssociatedObject.ViewportPointToLocation(
    new Point(AssociatedObject.ViewportSize.Width, 
              AssociatedObject.ViewportSize.Height));
}

So I basically take the point left top (0,0) and and use ViewportPointToLocation to convert it to a coordinate, and do the same think with the point that left bottom. And that’s all.

Now you can bind to the NorthWest and SouthEast property of the behavior and you get the view area in your view model. Be aware this works one way. It gets the view area to the ViewModel, not the other way around.

Contrary to my custom there’s no solution with the code in it, mostly because it’s already in the wp7nl library since yesterday. You can download the code from the library itself here, if you want.

06 June 2012

Detecting your Windows 8 app is running in the background

In Windows Phone life was so simple: when the user put your app in the background, as of version 7.5 the OS effectively froze all threads, timers and whatnot completely automatically. And it was automatically restarted too, if you used fast application switching. That kind of freeloading appeals to my natural programmer’s laziness so I put that to good use. That is, by doing nothing and letting the OS taking care of things.

Enter Windows 8: that has a even more sophisticated multi tasking system that allows things to actually keep running in the background. Excellent for most scenarios, but not if you are writing a game. I am currently porting Catch’em Birds to Windows 8 and observed that although the game music (thankfully) shuts up when the game is put in the background, the birds keep on flying and the timer keeps on running.

Now in App.Xaml.cs there is an OnSuspending method, but that is only called when the application is suspended – i.e., pushed out of memory. This is comparable to the point where a Windows Phone application would tombstone itself. You need to trap another event: VisibilityChanged of the current window.

In the OnLaunchedmethod of App.Xaml.cs, just above the Window.Current.Activate you can add

Window.Current.VisibilityChanged += Current_VisibilityChanged;
That gives a Windows.UI.Core.VisibilityChangedEventArgs which has a boolean Visible property that you can use like this:
void Current_VisibilityChanged(object sender, 
                               Windows.UI.Core.VisibilityChangedEventArgs e)
{
  System.Diagnostics.Debug.WriteLine("Visibile: " + e.Visible);
}

I am going to use this to send this event trough the MVVMLight messenger and adapt my game so that is reacts to this event – like in ‘stop the birds, or at least the timer. The OS being more capable actually requires me to do a wee bit more work. No more freeloading ;-)

06 May 2012

JSON deserialization with JSON.net: caching results

On January 22 I promised this to be a three-part series. I’ve been kinda busy with upgrading apps, Windows 8 experiments and trivial ;-) stuff like code camps, an MVP summit, preparing my first and second talk about Windows Phone and whatnot and made you wait for the final part for exactly three months – but those who know me, know I stick my promises, so here’s the third and final part of my JSON for Windows Phone series.

In part 1 of this series I described the basics of creating classes from a JSON string and then simply deserializing the string into a (list of) classes. In part 2 I showed how to use JSONConverter subclasses to handle complex stuff the deserializer cannot handle out of the box, like class hierarchies. Part 3, as promised, shows a way to cache results - which makes your application faster, more responsive and more battery/data plan friendly.

Using the demo solution of part 2 as a starting point, I first brought in my wp7nl library on codeplex using NuGet. I am lazy just like any programmer (should be) and I like to defer as much heavy lifting to already existing code as I can ;-).

When dealing with data downloaded from the web everything becomes asynchronous by nature (at least on Windows Phone), and since we don’t have the await and async keyboards aboard our platform yet, I tend to use Observables from Microsoft.Phone.Reactive. To let that work with events, I need an EventArgs child class for my “loading completed” delegate, which I have defined in the following trivial way:

using System;
using System.Collections.Generic;

namespace Wp7nl.Utilities
{
  public class DataLoadCompletedArgs<T> : EventArgs
  {
    public IList<T> Result { get; set; }

    public Exception Error { get; set; }
  }
}

It’s a generic class because I am basically too lazy to write casting statements everywhere. The basic setup of the helper class that does both loading itself is like this:

using System.Linq;
using Microsoft.Phone.Reactive;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net;
using Newtonsoft.Json;

namespace Wp7nl.Utilities
{
  public class CachedServiceDataLoader<T> where T : class
  {
    private readonly IsolatedStorageHelper<List<T>> storageHelper;

    public CachedServiceDataLoader()
    {
      storageHelper = new IsolatedStorageHelper<List<T>>();
    }

    private void FireDataLoadCompleted(IList<T> result, Exception error)
    {
      if (DataLoadCompleted != null)
      {
        DataLoadCompleted(this,
                          new DataLoadCompletedArgs<T> 
                          {Result = result, Error = error});
      }
    }

    public delegate void DataLoadCompletedHandler(object sender, 
      DataLoadCompletedArgs<T> args);

    public event DataLoadCompletedHandler DataLoadCompleted;
  }
}

So what have we here? A constructor that creates an IsolatedStorageHelper – that’s a class from the latest version from Wp7nl, where it sits in the Wp7nl.Utilities namespace. It’s basically the internal logic of the extension methods I described in my article about tombstoning MVVMLight viewmodels using SilverlightSerializer cut loose from those extension methods – so they can be used for caching all kinds of classes, and not only viewmodels on deactivation or closing of the app. The bottom part of the class is just the event indicating a data load action has been completed, and a convenience method to easily fire that event (I mentioned I was lazy, didn’t I? ;-) ) .

Next up is another little convenience methods for loading stuff from the cache or returning a default (empty) list if the results are not available:

private List<T> LoadFromStorage()
{
  return storageHelper.ExistsInStorage() ? 
     storageHelper.RetrieveFromStorage() : new List<T>();
}

It’s only used once, so I could just a easy have omitted it, but it makes the rest of the code a bit more readable and that’s important too. When you state your intentions in code, that saves on comment.

The method to read stuff from cache is a bit more complex than strictly necessary, but since data coming from the web is coming in asynchronously, why would I want my app to wait on my cache coughing up its results? So I made the cache retrieval asynchronously as well, using some old skool BackgroundWorker hoopla:

public bool StartLoadFromCache()
{
  if (storageHelper.ExistsInStorage())
  {
    var w = new BackgroundWorker();
    w.DoWork += (s, e) =>
      {
        e.Result = LoadFromStorage();
      };

    w.RunWorkerCompleted += (s, e) =>
      FireDataLoadCompleted(e.Result as List<T>, e.Error);

    w.RunWorkerAsync();
    return true;
  }
  return false;
}

I could have used an observable here as well I guess, but I still have not adapted my code snippet. So anyway, I cheat a little by checking first if there’s any cache data at all – if there is not, the method immediately returns false, informing the calling method there’s no cached data and to go get the stuff on the web. Which it can, incidentally, by calling the following method:

public void StartDownloadCacheData(IList<T> currentObjects, Uri serviceUri,
                                   params JsonConverter[] converters)
{
  var w = new SharpGIS.GZipWebClient();
  Observable.FromEvent<DownloadStringCompletedEventArgs>(
    w, "DownloadStringCompleted")
    .Subscribe(r =>
    {
      if (DataLoadCompleted != null)
      {
        if (r.EventArgs.Error == null)
        {
          var deserialized = 
               JsonConvert.DeserializeObject<List<T>>(r.EventArgs.Result,
                                                      converters);
          var result = new List<T>(currentObjects);
          result.AddRange(deserialized.Where(p => !currentObjects.Contains(p)));
          FireDataLoadCompleted(result, r.EventArgs.Error);
          storageHelper.SaveToStorage(result);
        }
        else
        {
          FireDataLoadCompleted(null, r.EventArgs.Error);
        }
      }
    });

  w.DownloadStringAsync(serviceUri);
}

So what this method does is pretty simple:

  • It makes a GZipWebClient (that allows data to be loaded zipped, thus saving on amount of bytes actually transmitted)
  • It makes an Observable from the event “DownloadStringCompleted” and subscribes an anonymous method
  • It fires the DownloadStringAsync method on the uri

Now the anonymous method that is fired when the data arrives

  • Checks for errors
  • Tries to deserialize the incoming data using the provides converters (if any)
  • Adds the existing object list to the result list
  • Add the new objects to the list after weeding out duplicates that were already in the list
  • Fires the complete event
  • Stores the now merged data set in isolated storage.

So the idea is that you can do consecutive downloads, but that resulting data never contains any duplicates. This is why you must provide the list of current objects. This may seem like a little odd, but this is exactly the thing you want to do with working with geographical data – which I do almost all the time for a living. As an inspector you want to download stuff from the areas you want to inspect, not the whole municipality. You move your map to a location, hit “download” and presto, you have the stuff you want to use cached on you device before you go on the road. Repeat until all areas you want to visit today have been processed. Kinda like Nokia Drive does – there is never enough room aboard your phone to store all the possible maps of the world, but when you to Seattle, you download the maps for Washington State, not the whole of North America, and you’re good to go.

But what if you want to start over – clearing the cache in stead of adding it? That’s the last method of this class:

public void StartClearStorage()
{
  var w = new BackgroundWorker();
  w.DoWork += (s, e) => storageHelper.DeletedFromStorage();

  w.RunWorkerCompleted += (s, e) =>
  {
    if (DataLoadCompleted != null)
    {
      FireDataLoadCompleted(new List<T>(), e.Error);
    }
  };

  w.RunWorkerAsync();
}

Also asynchronously, also not strictly necessary, but Microsoft tend to move toward doing everything asynchronously – if you have done any Windows 8 development you know performance requirements are pretty high and strict, so better get used to it already.

JSONdemo3I updated the demo solution to show off the workings of this class, that presents itself like showed to the right. If you click on “Load devices”, it will show four devices, as displayed on the image, and the message “Loading from web”. If you hit the “Load devices” button again, it will show the same four devices, but show the message “Loading from cache” and it will show them just a wee bit faster.

If you hit “Load more devices” you will see six devices, – with the Lumia 800 mentioned two times. But wait, what about weeding out the duplicates in StartDownloadCacheData – doesn’t that work? It sure does, but I already mentioned I was lazy, so I did not implement any “Equals” logic on  the Device class – that’s left as exercise for the reader ;-). I assure you it will work properly then.

“Clear list” just clears the list, and if you hit “Load devices” it will load the devices from cache again – very fast.

“Clear cache and list” will actually wipe the cache, so if you hit “Load devices” again it will show “Loading from web”.

I won’t bother you with the XAML – the code in MainPage.xaml.cs is pretty straightforward and shows off all the features of the CachedServiceDataLoader:

using System;
using System.Collections.Generic;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Reactive;
using Wp7nl.Utilities;

namespace JsonDemo
{
  public partial class MainPage : PhoneApplicationPage
  {
    private CachedServiceDataLoader<Device> cachedLoader;
    private IList<Device> currentData;
    public MainPage()
    {
      InitializeComponent();
      Loaded += MainPage_Loaded;
    }

    void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
      cachedLoader = new CachedServiceDataLoader<Device>();
      currentData = new List<Device>();
      Observable.FromEvent<DataLoadCompletedArgs<Device>>(
        cachedLoader, "DataLoadCompleted")
       .Subscribe(r =>
                    {
                      currentData = r.EventArgs.Result;
                      PhoneList.ItemsSource = r.EventArgs.Result;
                    });
    }

    private void Load_Click(object sender, RoutedEventArgs e)
    {
      if (!cachedLoader.StartLoadFromCache())
      {
        Message.Text = "Loading from web";
        cachedLoader.StartDownloadCacheData(currentData,
          new Uri("http://www.schaikweb.net/dotnetbyexample/JSONPhones2.txt"),
          new JsonDeviceConverter(), new JsonSpecsConverter());
      }
      else
      {
        Message.Text = "Loading from cache";        
      }
    }

    private void Load2_Click(object sender, RoutedEventArgs e)
    {
      Message.Text = "Loading from web";
      cachedLoader.StartDownloadCacheData(currentData,
        new Uri("http://www.schaikweb.net/dotnetbyexample/JSONPhones3.txt"),
        new JsonDeviceConverter(), new JsonSpecsConverter());
    }      

    private void Clear_Click(object sender, RoutedEventArgs e)
    {
      PhoneList.ItemsSource = null;
      Message.Text = "cleared list (not cache)";
    }

    private void ClearCache_Click(object sender, RoutedEventArgs e)
    {
      cachedLoader.StartClearStorage();
      Message.Text = "cleared list and cache";
    }
  }
}

There isn’t even any of my trademark MVVM code in here. In the MainPage_Loaded – not surprisingly - all the stuff is initialized. The CachedServiceDataLoader is created using a type T, and spits out a IList of T. I use an Observable to keep track of things here as well, but of course you are free to subscribe to events in the ‘old fashioned’ way.

Load_Click shows the usage of StartLoadFromCache and StartDownloadCacheData, the latter one using the JSONconverter child classes I showed in part 2. The rest I assume to be pretty straightforward.

As you can see, working with JSON on Windows Phone is dead easy and my little helper class makes it even more easy. I am still pondering if I should include this in the wp7nl library, as this creates yet two more dependencies (SharpGIS.GZipWebClient and Newtonsoft.Json) to keep in sync. If you have any feedback on this, I’d be happy to hear it. But anyway, this concludes my JSON for Windows Phone series, I hope it will prove to be a useful mini-tutorial for the Windows Phone developer community. And as usual, you can download the full solution from my website.

01 April 2012

Porting the DragFlickBehavior from Windows Phone 7 to Windows 8 Metro Style

Preface

A little over a year ago I made DragFlickBehavior, a behavior for Windows Phone that makes essentially anything draggable and ‘flickable’, that is, you can drag a GUI element along with your finger and it seems to have a little inertia when you let it go. In my previous post, I described the basics of how to make a behavior at all for Windows 8 Metro style. The testing of this was done using a ported version of the DragFlickBehavior. I’ve retraced my steps to how I got it to work, and will describe the process of porting an existing behavior here.

For the DragFlickBehavior to work, some groundwork needed to be layed first. For Windows Phone, I made a couple of extension methods for both FrameworkElement and StoryBoard first. To make matters worse, one of those extension methods in FrameworkElementExtensions used yet another extension method – GetVisualParent in VisualTreeHelperExtensions from Phone7.Fx… Nil desperandum… I’ll start at the beginning

Porting  VisualTreeHelperExtensions

I created a class library Win8nl.External, copied VisualTreeHelperExtensions.cs from it’s codeplex location, and opened the it the editor. And then the process was pretty simple:

  • The namespace System.Windows.Media is gone. So I deleted it’s using.
  • I basically clicked every red line, hit Control-.  (that’s Control-dot) and in most cases the editor would suggest a name space to add

In the end I seemed to have added

using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;

And then there was this slight matter of 2 places where the author calls VisualStateManager.GetVisualStateGroups and expects the result to be an IList. Now it’s an IEnumerable. Anyway, I solved this by changing the

IList groups = VisualStateManager.GetVisualStateGroups(root);

into

var groups = VisualStateManager.GetVisualStateGroups(root);

on both occasions. One file done. I won’t even pretend I understand what all those methods in this file are actually doing. I just ported them.

Porting FrameworkElementExtensions

I then created a library Win8nl, added references to Win8nl.External and WinRtBehaviors, and started on the FrameworkElementExtensions . This proved to be a pretty trivial matter. I needed to remove

using System.Windows.Controls;
using System.Windows.Media;
using System.Linq;
using Phone7.Fx;

And add after Control-dotting trough the errors I found I had added

using Windows.UI.Xaml.Media;
using Windows.UI.Xaml;
using Windows.Foundation
using Windows.UI.Xaml.Controls

Two files done!

Porting StoryboardExtensions

Routine starts to settle in. Remove

using System.Windows.Media;
using System.Windows.Media.Animation;
Control-dot around, and you will see you've added
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;

But then we hit our first snag. Two methods use a parameter of type IEasingFunction, that does no longer exist. But that can be fixed, by changing it into EasingFunctionBase.

Then I found out that Storyboard.SetTargetProperty apparently no longer wants to have a PropertyPath – which can be made from a DependencyProperty object – but a string. So method

public static void AddAnimation(this Storyboard storyboard,
 DependencyObject item, Timeline t, DependencyProperty p)
{
  if (p == null) throw new ArgumentNullException("p");
  Storyboard.SetTarget(t, item);
  Storyboard.SetTargetProperty(t, new PropertyPath(p));
  storyboard.Children.Add(t);
}
Need to be changed to
 public static void AddAnimation(this Storyboard storyboard,
 DependencyObject item, Timeline t, string property)
{
  if (string.IsNullOrWhiteSpace(property)) throw new ArgumentNullException("property");
  Storyboard.SetTarget(t, item);
  Storyboard.SetTargetProperty(t, property);
  storyboard.Children.Add(t);
}
This is bad news, since it breaks the public interface. And it breaks even more, namely another public extension method
public static void AddTranslationAnimation(this Storyboard storyboard,
   FrameworkElement fe, Point from, Point to, Duration duration,
   EasingFunctionBase easingFunction)
{
  storyboard.AddAnimation(
      fe.RenderTransform,
      storyboard.CreateDoubleAnimation(duration, from.X, to.X, easingFunction),
                                       CompositeTransform.TranslateXProperty);
  storyboard.AddAnimation(fe.RenderTransform,
       storyboard.CreateDoubleAnimation(duration, from.Y, to.Y, easingFunction),
                                        CompositeTransform.TranslateYProperty);
}
Needs to be changed to
public static void AddTranslationAnimation(this Storyboard storyboard,
  FrameworkElement fe, Point from, Point to, Duration duration,
  EasingFunctionBase easingFunction)
{
  storyboard.AddAnimation(fe.RenderTransform,
  storyboard.CreateDoubleAnimation(duration, from.X, to.X, easingFunction),
                                   "TranslateX");
  storyboard.AddAnimation(fe.RenderTransform,
  storyboard.CreateDoubleAnimation(duration, from.Y, to.Y, easingFunction),
                                   "TranslateY");
}

I must honestly say I find the apparent need to specify storyboard target properties verbatim, as in strings, quite peculiar, but apparently this is the way it needs to be done. I am only the messenger here.

Porting DragFlickBehavior

Here we go again. Delete
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Animation;
using Wp7nl.Utilities;
And Control-dotting learns you the following needs to be added:
using Win8nl.Utilities;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using WinRtBehaviors;
Soon after that, you'll learn that the second parameter of a ManipulationDelta event is no longer of type ManipulationDeltaEventArgs but of ManipulationDeltaRoutedEventArgs, and that it does no longer have a “DeltaManipulation” property but a plain “Delta” property. So the AssociatedObjectManipulationDelta method capturing the event was this:
void AssociatedObjectManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
  var dx = e.DeltaManipulation.Translation.X;
  var dy = e.DeltaManipulation.Translation.Y;
  var currentPosition = elementToAnimate.GetTranslatePoint();
  elementToAnimate.SetTranslatePoint(currentPosition.X + dx, currentPosition.Y + dy);
}
and now needs to be this
void AssociatedObjectManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
  var dx = e.Delta.Translation.X;
  var dy = e.Delta.Translation.Y;
  var currentPosition = elementToAnimate.GetTranslatePoint();
  elementToAnimate.SetTranslatePoint(currentPosition.X + dx, currentPosition.Y + dy);
}

No rocket science in there, right? And almost identical set of rework needs to be done to the method capturing ManipulationCompleted. Its second parameter was of type ManipulationCompletedEventArgs and is now – you’ve probably guessed it – ManipulationCompletedRoutedEventArgs. And that does no longer have a property e.FinalVelocities.LinearVelocity.X and Y but is does have a Velocities.Linear.X and Y.

For some reason though, those properties return values that are somewhere between 0 and 1, or at least it seems so. So I made a rule-of-thumb conversion multiplying them by 1000. Wrapping that up: AssociatedObjectManipulationCompleted used to be

private void AssociatedObjectManipulationCompleted(object sender,
                                                    ManipulationCompletedEventArgs e)
{
  // Create a storyboard that will emulate a 'flick'
  var currentPosition = elementToAnimate.GetTranslatePoint();
  var velocity = e.FinalVelocities.LinearVelocity;
  var storyboard = new Storyboard { FillBehavior = FillBehavior.HoldEnd };

  var to = new Point(currentPosition.X + (velocity.X / BrakeSpeed),
                     currentPosition.Y + (velocity.Y / BrakeSpeed));
  storyboard.AddTranslationAnimation(elementToAnimate, currentPosition, to, 
    new Duration(TimeSpan.FromMilliseconds(500)), 
    new CubicEase {EasingMode = EasingMode.EaseOut});
  storyboard.Begin();
}
and it now is
private void AssociatedObjectManipulationCompleted(object sender,
                                                   ManipulationCompletedRoutedEventArgs e)
{
  // Create a storyboard that will emulate a 'flick'
  var currentPosition = elementToAnimate.GetTranslatePoint();
  var xVelocity = e.Velocities.Linear.X * 1000;
  var yVelocity = e.Velocities.Linear.Y * 1000;
  var storyboard = new Storyboard { FillBehavior = FillBehavior.HoldEnd };
  var to = new Point(currentPosition.X + (xVelocity / BrakeSpeed),
                     currentPosition.Y + (yVelocity / BrakeSpeed));
  storyboard.AddTranslationAnimation(elementToAnimate, currentPosition, to,
      new Duration(TimeSpan.FromMilliseconds(500)),
   new CubicEase { EasingMode = EasingMode.EaseOut });
  storyboard.Begin();
}

The final thing you will need to take into consideration when you port behaviors is the fact that you used to have an OnAttached and Loaded event. You still have those, but by the very nature I implemented behaviors everything that happened in OnAttached and OnLoaded needs to be in OnAttached. Same goes for Unloaded and OnDetaching – the last one is fired by the first one. So follow the pattern I set out: initialize in OnAttached only, and only clean up in OnDetached.

So, the behavior used to have a setup like this:

protected override void OnAttached()
{
  base.OnAttached();
  AssociatedObject.Loaded += AssociatedObjectLoaded;
  AssociatedObject.ManipulationDelta += AssociatedObjectManipulationDelta;
  AssociatedObject.ManipulationCompleted += AssociatedObjectManipulationCompleted;
}

void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
{
  elementToAnimate = AssociatedObject.GetElementToAnimate();
  if (!(elementToAnimate.RenderTransform is CompositeTransform))
  {
    elementToAnimate.RenderTransform = new CompositeTransform();
    elementToAnimate.RenderTransformOrigin = new Point(0.5, 0.5);
  }
}
And that should now be 
protected override void OnAttached()
{
  elementToAnimate = AssociatedObject.GetElementToAnimate();
  if (!(elementToAnimate.RenderTransform is CompositeTransform))
  {
    elementToAnimate.RenderTransform = new CompositeTransform();
    elementToAnimate.RenderTransformOrigin = new Point(0.5, 0.5);
  }
  AssociatedObject.ManipulationDelta += AssociatedObjectManipulationDelta;
  AssociatedObject.ManipulationCompleted += AssociatedObjectManipulationCompleted;
  AssociatedObject.ManipulationMode = 
    ManipulationModes.TranslateX | ManipulationModes.TranslateY;
  base.OnAttached();
}
Notice a couple of interesting things:
  • The capture of “Loaded” is gone. We don’t need that any longer
  • There is an extra last line, setting the “ManipulationMode”. Apparently you need to set that up to make ManipulationDelta and ManipulationCompleted happen at all. It accidently stumbled upon that

Finally, the last part: OnDetaching. It used to be

protected override void OnDetaching()
{
  AssociatedObject.Loaded -= AssociatedObjectLoaded;
  AssociatedObject.ManipulationCompleted -= AssociatedObjectManipulationCompleted;
  AssociatedObject.ManipulationDelta -= AssociatedObjectManipulationDelta;

  base.OnDetaching();
}
And the only thing that needs to be changed to use that is the removal of the first line: AssociatedObject.Loaded -= AssociatedObjectLoaded;;

And then we’re done. If you add this behavior to any object on the screen, like I showed in the previous post:

<Page
  x:Class="Catchit8.BlankPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="using:Catchit8"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:Win8nl_Behaviors="using:Win8nl.Behaviors"
  xmlns:WinRtBehaviors="using:WinRtBehaviors"
  mc:Ignorable="d">

  <Grid Background="{StaticResource ApplicationPageBackgroundBrush}">
    <TextBlock HorizontalAlignment="Left" Margin="503,213,0,0" TextWrapping="Wrap" 
   VerticalAlignment="Top" FontSize="18" Text="Drag me">
      <WinRtBehaviors:Interaction.Behaviors>
         <Win8nl_Behaviors:DragFlickBehavior BrakeSpeed ="5"/>
      </WinRtBehaviors:Interaction.Behaviors>
    </TextBlock>
    <Button Content="Drag me too!" HorizontalAlignment="Left" Margin="315,269,0,0" 
   VerticalAlignment="Top" >
      <WinRtBehaviors:Interaction.Behaviors>
          <Win8nl_Behaviors:DragFlickBehavior BrakeSpeed ="5"/>
      </WinRtBehaviors:Interaction.Behaviors>
     </Button>

  </Grid>
</Page>

You will get an effect like this (I added a slider just for kicks)

DragFlickBehavior on Windows 8 demonstrated

Conclusion

At first glance, Windows 8 development does not seem to differ that much from Windows Phone development. After I made my behavior framework, porting a fairly complex behavior like this was pretty easy, so I’d say that holds true at second glance as well. Sure, some things are different – mostly namespaces and some property names. The XAML is a wee bit different as well. As to why Microsoft have decided to change namespaces, rename properties or methods or even let return values be a bit different – I don’t know. What I do know is that bitching about it will probably raise your blood pressure but it won’t help you very much as a developer. Just think of this: Microsoft sold 450 million copies of Windows 7. I don’t think those will all be Windows 8 next year, but I think the 100 million mark will be hit pretty soon. The choice is yours – either you are spending time and energy on getting angry that Microsoft moved your cheese (or actually, only some of it) or you can go out and find new and probably a bloody lot of cheese.

Well, I’ve made my choice

As usual, a complete demo solution for those who, like me, are too lazy to do all the typing themselves, can be found here. So you can get started even faster. ¡Arriba! ¡Andale! ;-)