31 December 2011

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

Note: an update to this article has been written here

On New Year’s Eve I can’t help but writing this last bit of 2011: yesterday on a #wp7nl developer’s meet up, which was basically a free-for-all fun hacking event organized by Matthijs Hoekstra, I wrote a little thingy for Windows Phone 7 that accepts a string, tries to find an image for it using Bing Image search and displays it as a background. Of course it’s a behavior – I write behaviors a dozen, because the concept of reusable dynamic behavior is something that fits very well with the way I think. Call me the behaviornator if you like ;-)

It’s very simple, it’s quite fun, demonstrates a little Rx usage, makes quite unusual use of the Bing Image Search api - and it will play a supporting act in my newest Windows Phone 7 app. The basic structure of the behavior is set up utilizing the #wp7nl library SafeBehavior that I described earlier:

using System;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Phone.Reactive;
 
namespace Wp7nl.Behaviors
{
  /// <summary>
  /// A behavior that puts an image on the background of the Attched object
  /// using Bing Image Search
  /// </summary>
  public class DynamicBackgroundBehavior : SafeBehavior<Panel>
  {
    private ImageBrush backgroundBrush;
    
    public DynamicBackgroundBehavior()
    {
      Opacity = 1.0;
    }

    #region SearchString
    public const string SearchStringPropertyName = "SearchString";

    /// <summary>
    /// The search string to be used on Bing Maps
    /// </summary>
    public string SearchString
    {
      get { return (string)GetValue(SearchStringProperty); }
      set { SetValue(SearchStringProperty, value); }
    }

    public static readonly DependencyProperty SearchStringProperty = 
        DependencyProperty.Register(
        SearchStringPropertyName,
        typeof(string),
        typeof(DynamicBackgroundBehavior),
        new PropertyMetadata(String.Empty, SearchStringChanged));

    public static void SearchStringChanged(DependencyObject d, 
                                           DependencyPropertyChangedEventArgs e)
    {
      var behavior = d as DynamicBackgroundBehavior;
      if (behavior != null)
      {
        behavior.StartGetFirstImage((string)e.NewValue);
      }
    }
    #endregion

    /// <summary>
    /// Bing search key
    /// </summary>
    public string BingSearchKey { get; set; }

    /// <summary>
    /// Stretch used for the image
    /// </summary>
    public Stretch Stretch { get; set; }

    /// <summary>
    /// Opacity used for the image
    /// </summary>
    public double Opacity { get; set; }
  }
}

In short, this behavior has four properties:

  • Opacity
  • Stretch
  • BingSearchKey
  • SearchString

BingSearchApiOpacity and Stretch are just simple properties for the images that is going to be displayed. SearchString is the string that’s going to be used to find an image for. This is a dependency property – so it can be used in data binding. Note the SearchStringChanged method – this is called when the SearchString property changes. That in turn is firing the method StartGetFirstImage, that will start the actual search.

BingSearchKey is a 40-character long string identifying your application. You have to create a key for your application on the Bing Developer portal. Click the left button (“Sign in – Bing Search API”) and fill in the form depicted to the right(click for larger image).

Note: the behavior references Microsoft.Phone.Reactive – so the project holding this should Microsoft.Phone.Reactive.dll and System.Observable.dll

Moving on to the setup of the behavior, which is very simple now since we are building upon the SafeBehavior:

/// <summary>
/// Setup the behavior
/// </summary>
protected override void OnSetup()
{
  backgroundBrush = new ImageBrush
  {
    Stretch = Stretch,
    Opacity = Opacity
  };

  // Set the image brush to the background of the Panel 
  AssociatedObject.Background = backgroundBrush;
}

Simply put: create an Image brush using the property settings, and put it as background on the GUI element to which the behavior is attached.

The method that’s called from SearchStringChanged (which is fired as the SearchString dependency property changes) is implemented as showed below:

/// <summary>
/// Start the image request using Bing Serach
/// </summary>
/// <param name="searchString"></param>
protected void StartGetFirstImage(string searchString)
{
  var queryUri = 
    string.Format(
      "http://api.bing.net/xml.aspx?Appid={0}&query={1}&sources=image",
      BingSearchKey, searchString);
  var request = WebRequest.Create(queryUri) as HttpWebRequest;
  var response = 
    Observable.FromAsyncPattern<WebResponse>(
      request.BeginGetResponse, request.EndGetResponse)();
  response.Subscribe(WebClientOpenReadCompleted, WebClientOpenReadError);
}

An Uri is formed using the BingSearchKey and the actual search string – and the clause “sources=image”, telling Bing to return images. That Uri is fed to a standard WebRequest. And then the Rx framework comes into play to easily process the async read process. The Observable.FromAsyncPattern and Subscribe usage has the distinct advantage of not having to attach all kind of event handlers, trap errors with try-catch blocks, and not forgetting to detach the event handlers when the reading is done. The Rx framework handles this all, so I don’t have to worry about that.

The final piece of the behavior – the actual processing of the image:

/// <summary>
/// Called when image search returns
/// </summary>
/// <param name="result"></param>
private void WebClientOpenReadCompleted(WebResponse result)
{
  using (var stream = result.GetResponseStream())
  {
    using (var reader = XmlReader.Create(stream,
       new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore }))
    {
      var doc = XDocument.Load(reader);

      // Get the first image from the result
      XNamespace ns = "http://schemas.microsoft.com/LiveSearch/2008/04/XML/multimedia";
      if (doc.Root != null)
      {
        var firstImage = doc.Root.Descendants(ns + "MediaUrl").FirstOrDefault();
        if (firstImage != null)
        {
          Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
              var bi = new BitmapImage
                {
                  UriSource = new Uri(firstImage.Value),
                  CreateOptions = BitmapCreateOptions.BackgroundCreation
                };
              backgroundBrush.ImageSource = bi;
            });
        }
      }
    }
  }
}

/// <summary>
/// Called upon a search error (not used)
/// </summary>
/// <param name="ex"></param>
private void WebClientOpenReadError(Exception ex)
{
}

Since the xml.aspx page is referenced, Bing returns the result as a xml document. If you are interested in the details of the Bing Search result, feel free to explore the xml document – this code basically just finds the first “MediaUrl” tag, makes a BitMapImage from it, and puts the result into the backgroundBrush. And we’re done.

carrotdemoPut this behavior on a descendant of Panel (a Grid, for instance), fill the BingSearchKey property with a valid key, databind the “SearchString” property to a string in a ViewModel and as soon as the value of SearchString changes, the behavior will show the first available image returned by Bing Image search as a background on that grid.

I’ve put together a small demo application containing and demonstrating the behavior. It deviates in two ways from my usual mode of operation. First, does not run out of the box – you will have to get your own Bing Search API key first. Second: it does not use MVVM – I’ve data bound the behavior’s SearchString property directly to a TextBox’s Text property, which makes the behavior start to search for background immediately as you start typing, as showed to the left. So if you type “carrot” in the textbox you get, well – an image showing carrots ;-)

 

Well, that’s all for 2011. A very special year from me with some ups and downs, with getting a Windows Phone Development MVP award definitely being the top event in the "ups" category. Now onwards to 2012, which I think will prove to be a very exciting year indeed. I hope you all will continue to enjoy this blog as I did - and you apparently did in 2011 as well.

03 December 2011

Re-imagining the behavior to show the Windows Phone 7 camera as background

This blog turns out not only to be a collection of how-to samples but also a record of my evolution as a Windows Phone 7 developer. At the end of my previous post, Safe event detachment base class for Windows Phone 7 behaviors, I promised a usage example and I decided to re-implement the behavior to show the Windows Phone 7 camera as background using the SafeBehavior as a base class. This makes the code considerable easier.

The base setup of the re-implemented behavior is pretty simple:

using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Navigation;
using Microsoft.Devices;
using Microsoft.Phone.Controls;

namespace Wp7nl.Behaviors
{
  /// <summary>
  /// A behavior that shows a camera view on the background of a panel
  /// </summary>
  public class CameraViewBackgroundBehavior : SafeBehavior<Panel>
  {

    private PhotoCamera camera;
    private VideoBrush backgroundBrush;

    public CameraViewBackgroundBehavior()
    {
      ListenToPageBackEvent = true;
    }
  }
}

Note this behavior needs to detect the user navigating back to the page – this in necessary because we need to do something with the camera.

In stead of all the song and dance for attaching and detaching events using the snippet I published earlier, it’s now a matter of overriding the OnSetup and OnCleanup methods to initialize the camera:

protected override void OnSetup()
{
  if (camera == null)
  {
    camera = new PhotoCamera();
    ParentPage.OrientationChanged += ParentPageOrientationChanged;
  }

  // Create a video brush with the right parameters
  backgroundBrush = new VideoBrush
                      {
                        Stretch = Stretch.UniformToFill,
                        AlignmentX = AlignmentX.Left,
                        AlignmentY = AlignmentY.Top
                      };

  // Set the video brush to the background of the panel 
  // and and do an initial display
  AssociatedObject.Background = backgroundBrush;
  backgroundBrush.SetSource(camera);
  SetVideoOrientation(ParentPage.Orientation);
}

protected override void OnCleanup()
{
  ParentPage.OrientationChanged -= ParentPageOrientationChanged;
  camera.Dispose();
  camera = null;
}

This behavior also needs to do some action when the user actually navigates back to the page, which you can do by override the OnParentPageNavigated method - in this case, re-initializing the whole behavior

/// <summary>
/// Fired whe page navigation happens
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected override void OnParentPageNavigated(object sender, NavigationEventArgs e)
{
  // Re-setup when this page is navigated BACK to
 if( IsNavigatingBackToBehaviorPage(e))
 {
   if (camera != null)
   {
     OnCleanup();
     OnSetup();
   }
  }
}

The actual implementation of showing the camera background has hardly changed, and is only mentioned here for the sake of completeness:

private void ParentPageOrientationChanged(object sender, OrientationChangedEventArgs e)
{
  SetVideoOrientation(e.Orientation);
}

/// <summary>
/// Sets background video brush parameters based upon page orientation
/// </summary>
/// <param name="orientation"></param>
private void SetVideoOrientation(PageOrientation orientation)
{
  System.Diagnostics.Debug.WriteLine("Switching to {0}", orientation);
  switch (orientation)
  {
    case PageOrientation.PortraitUp:
      backgroundBrush.Transform = 
        new CompositeTransform { Rotation = 90, TranslateX = 480 };
      break;
    case PageOrientation.LandscapeLeft:
      backgroundBrush.Transform = null;
      break;
    case PageOrientation.LandscapeRight:
      if (Microsoft.Phone.Shell.SystemTray.IsVisible )
      {
        backgroundBrush.Transform = 
          new CompositeTransform { Rotation = 180, TranslateX = 728, TranslateY = 480 };
      }
      else
      {
        backgroundBrush.Transform = 
            new CompositeTransform { Rotation = 180, TranslateX = 800, TranslateY = 480 };
      }
      break;
  }
}

As this post demonstrated, using the SafeBehavior as a base class makes life a lot easier than implementing the whole pattern over and over again, even when using a snippet.

Code is part of the the #wp7nl library on codeplex and can be found here

26 November 2011

Safe event detachment base class for Windows Phone 7 behaviors

Some time ago I blogged about the Safe Event Detachment ‘pattern’ for behaviors and even included a snippet that made implementing this pattern easier. When I started to use this pattern more often myself I observed quite some code duplication appearing and I don’t like that. What’s more – although the pattern works well under Silverlight and WPF, there are some unique situations in Windows Phone 7 that need some extra attention – particularly the situation in which the user is navigating back to a page containing such a behavior. For when the user is navigation from the page, the AssociatedObject’s Unloaded event fires and the behavior is de-activated. If the user then moves back to the page – the AssociatedObject’s OnAttached event is not fired and the behavior is not re-initialized.

So I set out to create a base class taking care of most of this initalization hooplah without bothering the developer too much. This turned out to be not so simple as I thought. But anyway – thinks worked out. The initial setup of the base class is like this:
using System;
using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;

namespace Wp7nl.Behaviors
{
  /// <summary>
  /// A base class implementing the safe event detachment pattern for behaviors.
  /// Optional re-init after page back navigation.
  /// </summary>
  /// <typeparam name="T">The framework element type this behavior attaches to</typeparam>
  public abstract class SafeBehavior<T> : Behavior<T> where T : FrameworkElement
  {
    protected SafeBehavior()
    {
      IsCleanedUp = true;
    }

    /// <summary>
    ///Setting this value to true in the constructor makes the behavior
    ///re-init after a page back event.
    /// </summary>
    protected bool ListenToPageBackEvent { get; set; }

    /// <summary>
    /// The page this behavior is on
    /// </summary>
    protected PhoneApplicationFrame ParentPage;

    /// <summary>
    /// The uri of the page this behavior is on
    /// </summary>
    private Uri pageSource;

    protected override void OnAttached()
    {
      base.OnAttached();
      InitBehavior();
    }

    /// <summary>
    /// Does the initial wiring of events
    /// </summary>
    protected void InitBehavior()
    {
      if (IsCleanedUp)
      {
        IsCleanedUp = false;
        AssociatedObject.Loaded += AssociatedObjectLoaded;
        AssociatedObject.Unloaded += AssociatedObjectUnloaded;
      }
    }
  }
}

The comments already give away which direction this is going to take: the behavior keeps track of the page it’s on and that page’s uri to track if the user is navigating back to this page. If you don’t want this behavior, do nothing. If you need to track the user navigating back to the page (and believe me, in Windows Phone 7 you want that in most of the cases), set ListenToPageBackEvent to true in the behavior’s constructor. The setting up of this tracking is done in the next method:

/// <summary>
/// Does further event wiring and initialization after load
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
{
  // Find the page this control is on and listen to its orientation changed events
  if (ParentPage == null && ListenToPageBackEvent)
  {
    ParentPage = Application.Current.RootVisual as PhoneApplicationFrame;
    pageSource = ParentPage.CurrentSource;
    ParentPage.Navigated += ParentPageNavigated;
  }
  OnSetup();
}

/// <summary>
/// Fired whe page navigation happens
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ParentPageNavigated(object sender, NavigationEventArgs e)
{
  // Re-setup when this page is navigated BACK to
  if (IsNavigatingBackToBehaviorPage(e))
  {
    if (IsCleanedUp)
    {
      InitBehavior();
    }
  }
  OnParentPageNavigated(sender, e);
}

/// <summary>
/// Checks if the back navigation navigates back to the page
/// on which this behavior is on
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
protected bool IsNavigatingBackToBehaviorPage(NavigationEventArgs e)
{
  return (e.NavigationMode == NavigationMode.Back && e.Uri.Equals(pageSource));
}

Now if you have set ListenToPageBackEvent to true, it keeps the root visual (i.e. the page on which the behavior is plonked) in ParentPage, it’s uri in pageSouce and attaches an listener to the ParentPageNavigated event of this page. Now if a navigation event happens, the IsNavigatingBackToBehaviorPage checks by comparing uri’s if the user is actually navigating back to this page.

All very interesting, but the most important is: there are two methods OnSetup and OnParentPageNavigated in this class which are called. They are basically emtpy and form your hook points into this:

/// <summary>
/// Override this to add your re-init
/// </summary>    
protected virtual void OnParentPageNavigated(object sender, NavigationEventArgs e)
{     
}

/// <summary>
/// Override this to add your own setup
/// </summary>
protected virtual void OnSetup()
{
}

So far for the setup stuff: the cleanup stuff is a lot simpler:

protected bool IsCleanedUp { get; private set; }

/// <summary>
/// Executes at OnDetaching or OnUnloaded (usually the last)
/// </summary>
private void Cleanup()
{
  if (!IsCleanedUp)
  {
    AssociatedObject.Loaded -= AssociatedObjectLoaded;
    AssociatedObject.Unloaded -= AssociatedObjectUnloaded;
    OnCleanup();
    IsCleanedUp = true;
  }
}

protected override void OnDetaching()
{
  Cleanup();
  base.OnDetaching();
}

private void AssociatedObjectUnloaded(object sender, RoutedEventArgs e)
{
  Cleanup();
}

/// <summary>
/// Override this to add your own cleanup
/// </summary>
protected virtual void OnCleanup()
{
}

And once again you see a simple virtual Cleanup you can override.

I realize this is all very theoretical and technical, and the question you probably have now is – so what is this for and how do you use it? The usage is simple:

  • You create a MyBehavior<T> that descends from SafeBehavior<T>
  • If you want your behavior to re-init when the user navigates back set ListenToPageBackEvent  to true in the MyBehavior constructor. But beware. By its very nature the Navigated event is not detached. So basically you are leaking memory. Therefore, if you make a lot of behaviors, like in a game, don’t ever set ListenToPageBackEvent to true.Use with care and moderation.
  • You do setting up events in an override of OnSetup
  • You do cleaning up of events in an override of OnCleanup
  • And if you want to do something extra when the user is navigating back to the page do that in an override of OnParentPageNavigated.

This makes implementing the Safe Event Detachment ‘pattern‘ way more easy. This new behavior base is now included in my wp7nl library on codeplex and the source can be found here. A sample usage of this base class can be found here.

22 November 2011

Using MVVMLight, ItemsControl, Blend and behaviors to make a ‘heads up compass’

When I talk of the MVVM pattern, people usually think of business objects that get wrapped by ViewModels which get data bound to a user interface. Usually this is something like a list of people, news, items that can be purchased, whatever – and usually this data is displayed in a list box, with a bit of templating if it isn’t too much trouble. That’s fine in itself and good way to use my favorite pattern but there are more things possible using MVVM data binding than most people imagine. The most fun way I have been able to discover is to combine ItemsControl and behaviors. This is what drives my game Catch’em Birds. And this article shows how to use this technique make a kind of heads up compass. I’ll sprinkle some ‘how to do things in Blend’ (like adding and configuring behaviors) throughout the article as well.

For the hasty readers: “Setting the stage”, “Building the models” and “Building the ViewModel” is the ground work. The real stuff starts at “Initial user interface”.

Setting the stage

  • Create a new Windows Phone 7 application. Let’s call it “HeadsUpCompass”. Select Windows Phone 7.1 - duh ;).
  • Install my wp7nl library from codeplex via NuGet. This will get you some of my stuff and MVVMLight and some more stuff as well in one go.
  • Add references to Microsoft.Device.Sensors and Microsoft.Xna.Framework.

Building the models

The application has two models: CompassDirectionModel – holding stuff that wants to be displayed, and CompassModel, that checks the compass direction using the motion API. The CompassModel is implemented below. I’ve explained using the Motion API to check where the camera is looking in an earlier post so I’ll skip the details here. It’s basically the same functionality, wrapped in a model, with an event firing at the end:

using System;
using System.Windows;
using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;

namespace HeadsUpCompass.Models
{
  public class CompassModel
  {
    Motion motion;

    /// <summary>
    /// Inits this instance.
    /// </summary>
    public void Init()
    {
      // Check to see if the Motion API is supported on the device.
      if (!Motion.IsSupported)
      {
        MessageBox.Show("the Motion API is not supported on this device.");
        return;
      }

      // If the Motion object is null, initialize it and add a CurrentValueChanged
      // event handler.
      if (motion == null)
      {
        motion = new Motion {TimeBetweenUpdates = TimeSpan.FromMilliseconds(250)};
        motion.CurrentValueChanged += MotionCurrentValueChanged;
      }

      // Try to start the Motion API.
      try
      {
        motion.Start();
      }
      catch (Exception)
      {
        MessageBox.Show("unable to start the Motion API.");
      }
    }

        /// <summary>
    /// Stops this instance.
    /// </summary>
    public void Stop()
    {
      motion.Stop();
      motion.CurrentValueChanged -= MotionCurrentValueChanged;
    }

    /// <summary>
    /// Fired when a direction change is detected
    /// </summary>
    void MotionCurrentValueChanged(object sender, 
                                   SensorReadingEventArgs<MotionReading> e)
    {
      var yaw = MathHelper.ToDegrees(e.SensorReading.Attitude.Yaw);
      var roll = MathHelper.ToDegrees(e.SensorReading.Attitude.Roll);
      var pitch = MathHelper.ToDegrees(e.SensorReading.Attitude.Pitch);

      if (roll < -20 && roll > -160)
      {
        SetNewCompassDirection(360 - yaw + 90);
      }
      else if (roll > 20 && roll < 160)
      {
        SetNewCompassDirection(360 - yaw - 90);
      }
      else if (pitch > 20 && pitch < 160)
      {
        SetNewCompassDirection(-yaw );
      }
      else if (pitch < -20 && pitch > -160)
      {
        SetNewCompassDirection(360 - yaw + 180);
      }
    }

    private void SetNewCompassDirection(double compassDirection)
    {
      if (compassDirection > 360)
      {
        compassDirection -= 360;
      }
      if (compassDirection < 0)
      {
        compassDirection += 360;
      }

      if (CompassDirectionChanged != null)
      {
        CompassDirectionChanged(Convert.ToInt32(Math.Round(compassDirection)));
      }
    }

    // Event communicating compass direction change to outside world
    public event CompassDirectionChangedHandler CompassDirectionChanged;
    
    public delegate void CompassDirectionChangedHandler(int newDirection);
  }
}

The stuff that gets displayed has it’s own model, and is very simple:

using System.Collections.Generic;

namespace HeadsUpCompass.Models
{
  public class CompassDirectionModel
  {
    public int Direction { get; set; }

    public string Text { get; set; }

    public static IEnumerable<CompassDirectionModel> GetCompassDirections()
    {
      return new List<CompassDirectionModel>
      {
        new CompassDirectionModel {Direction = 0, Text = "N"},
        new CompassDirectionModel {Direction = 45, Text = "NE"},
        new CompassDirectionModel {Direction = 90, Text = "E"},
        new CompassDirectionModel {Direction = 135, Text = "SE"},
        new CompassDirectionModel {Direction = 180, Text = "S"},
        new CompassDirectionModel {Direction = 225, Text = "SW"},
        new CompassDirectionModel {Direction = 270, Text = "W"},
        new CompassDirectionModel {Direction = 315, Text = "NW"}
      };
    }
  }
}

And most of is a static factory method too that I, being a lazy programmer, just plonked into a class. This model accepts a text and a compass direction where it wants to be displayed. You can limit or add whatever you like.

Building the ViewModel

So far it has not been quite rocket science, and neither is the only ViewModel that is employed in this solution:

using System.Collections.ObjectModel;
using System.Windows;
using GalaSoft.MvvmLight;
using HeadsUpCompass.Models;

namespace HeadsUpCompass.ViewModels
{
  public class CompassViewModel : ViewModelBase
  {
    private readonly CompassModel model;

    public CompassViewModel()
    {
      model = new CompassModel();
      model.CompassDirectionChanged += ModelCompassDirectionChanged;
      CompassDirections = 
        new ObservableCollection<CompassDirectionModel>(
          CompassDirectionModel.GetCompassDirections());
      if( !IsInDesignMode) model.Init();
    }

    void ModelCompassDirectionChanged(int newDirection)
    {
      Deployment.Current.Dispatcher.BeginInvoke(
        () => { CompassDirection = newDirection; });
    }

    private int compassDirection;
    public int CompassDirection
    {
      get { return compassDirection; }
      set
      {
        if (compassDirection != value)
        {
          compassDirection = value;
          RaisePropertyChanged(() => CompassDirection);
        }
      }
    }

    private ObservableCollection<CompassDirectionModel> compassDirections;
    public ObservableCollection<CompassDirectionModel> CompassDirections
    {
      get { return compassDirections; }
      set
      {
        if (compassDirections != value)
        {
          compassDirections = value;
          RaisePropertyChanged(() => CompassDirections);
        }
      }
    }
  }
}

The ViewModel creates a CompassDirectionModel and subscribes to its events, and fills an observable collection with CompassDirectionModels – so basically a list of texts and the direction in which they want to be displayed.

Initial user interface

First of all, open MainPage.xaml, set shell:SystemTray.IsVisible="false", SupportedOrientations="PortraitOrLandscape" and then delete the grid “LayoutRoot” and everything inside it (and get rid of the App Bar sample code that commented out as well, that clears the stage). Replace it by this:

<Grid x:Name="LayoutRoot" >
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="*"/>
  </Grid.RowDefinitions >

  <!--TitlePanel contains the name of the application and page title-->
  <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
    <TextBlock x:Name="ApplicationTitle" Text="HeadsUp Compass" 
      Style="{StaticResource PhoneTextNormalStyle}"/>
  </StackPanel>

  <!--ContentPanel - place additional content here-->
  <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <Grid>
      <Grid.RowDefinitions>
        <RowDefinition Height="0.7*"/>
        <RowDefinition Height="0.3*"/>
      </Grid.RowDefinitions >
    <ItemsControl x:Name="CompassItems" ItemsSource="{Binding CompassDirections}"
           Grid.Row="0">
      <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
          <Canvas Background="Transparent" />
        </ItemsPanelTemplate>
      </ItemsControl.ItemsPanel>
      <ItemsControl.ItemTemplate>
        <DataTemplate>
          <Grid>
            <TextBlock Text="{Binding Text}" FontSize="48" Foreground="Red"/>
          </Grid>
        </DataTemplate>
      </ItemsControl.ItemTemplate>
    </ItemsControl>

    <TextBlock TextWrapping="Wrap" Text="{Binding CompassDirection}" 
       VerticalAlignment="Top" Margin="0,10,0,0" FontSize="48" Foreground="Red" 
       HorizontalAlignment="Center" Grid.Row="1"/>
    </Grid>
  </Grid>
</Grid>

The interesting part I’ve marked red. This is an ItemsControl - nothing more than a simple repeater. The declaration used in this article uses two templates: an ItemsPanelTemplate, which describes what all the bound items are rendered upon – in this case, a transparent canvas – and an ItemTemplate, which describes how each individual item in the CompassDirections property bound to the control itself is displayed – in this case, a grid with a simple text bound to a Text property. But on the ItemTemplate you can put literally everything you can dream. Including behaviors.

Setting up data binding using Expression Blend

First let’s get the data binding done. This is considerably easier using Expression Blend. Compile the application so far, and open it up in Expression Blend. Then use the following workflow:DataSource

  • On the top right hand side, select the “Data” tab
  • Click the Icon on the right that gives as tooltip “Create data source”
  • Select “Create Object DataSource”
  • Select “CompassViewModel” in the popup that appears.
  • Drag “CompassViewModel” under “CompassViewModelSource on top of the “LayoutRoot” grid in the Objects and Timeline Panel to the left bottom

Bound

If you have done things correctly, you should immediately see appear a red zero in the horizontal middle of your screen a little below the center, and a lot of texts stacked upon each other in the top left op your screen.

The fun thing is, this application already works more or less. If you deploy this on a device and fire it up, you will already see that the 0 starts to display the compass direction in degrees. But the compass direction texts are still stacked upon each other in the top left corner. Now it’s time for the coupe de grâce: a behavior that dynamically changes the location of the compass direction texts.

Location calculation

The behavior actually consist out of two parts: the LocationCalculator class and the actual CompassDirectionDisplayBehavior. I pulled the actual location calculation out of the behavior because I had to cobble it together by trial and error – and adding it to a test project by means of a link and testing it by unit tests made this a lot easier. Anyway, the code itself it pretty small: most of it is comments and properties:

using System;
using System.Windows;

namespace ARCompass.Behaviors
{
  /// <summary>
  /// Calculates screen positions based upon compass locations
  /// </summary>
  public class LocationCalcutator
  {
    /// <summary>
    /// Initializes a new instance of the LocationCalcutator class.
    /// Sets some reasonable defaults
    /// </summary>
    public LocationCalcutator()
    {
      Resolution = (6 * 800 / 360);
      CanvasHeight = 800;
      CanvasWidth = 480;
      ObjectWidth = 10;
    }

    /// <summary>
    /// Gets or sets the resolution (i.e. the pixels per degree
    /// </summary>
    public int Resolution { get; set; }

    /// <summary>
    /// The compass direction where the object to calculate for is located
    /// </summary>
    public int DisplayCompassDirection { get; set; }

    /// <summary>
    /// Gets or sets the width of the canvas.
    /// </summary>
    public double CanvasWidth { get; set; }

    /// <summary>
    /// Gets or sets the height of the canvas.
    /// </summary>
    public double CanvasHeight { get; set; }

    /// <summary>
    /// Gets or sets the width of the object (in pixels)
    /// </summary>
    public double ObjectWidth { get; set; }

    /// <summary>
    /// Sets the horizontal pixels.
    /// </summary>
    /// <param name="pixels">The pixels.</param>
    public void SetHorizontalPixels(double pixels)
    {
      Resolution = Convert.ToInt32(Math.Round(pixels/360));
    }

    /// <summary>
    /// Calculates the screen position.
    /// </summary>
    /// <param name="compassDirection">The compass direction the screen is 
    /// currently looking at.</param>
    /// <returns></returns>
    public Point CalculateScreenPosition(int compassDirection)
    {
      if (!(double.IsNaN(CanvasHeight) || double.IsNaN(CanvasWidth)))
      {
        var y = CanvasHeight / 2;
        var deltaDegrees1 = compassDirection - DisplayCompassDirection;
        var deltaDegrees2 = compassDirection - DisplayCompassDirection - 360;
        var deltaDegrees = 
           Math.Abs(deltaDegrees1) < Math.Abs(deltaDegrees2) ? 
             deltaDegrees1 : deltaDegrees2;

        var dx = deltaDegrees * Resolution;
        var x = Convert.ToInt32(CanvasWidth / 2) - dx;
        return new Point(x, y);
      }
      return new Point(-1000, -1000);
    }

    /// <summary>
    /// Determines whether the specified point is visible in the current canvas
    /// </summary>
    public bool IsVisible(Point point)
    {
      var overshoot = Convert.ToInt32(Math.Round(ObjectWidth/2 + 5));
      return (point.X > -overshoot && point.X < CanvasWidth + overshoot);
    }
  }
}

Resolution is a pretty weird property and is the base for all other calculations. It basically says – how many pixels is 1 degree? Default I set it to 6 * 800 / 360 = 13.333, which basically means if you move your camera 1 degree to the left whatever is displayed on your screen moves 13 pixels to the right.

The CalculateScreenPosition method basically is my way to calculate the screen position of an object in direction compassDirection, without using trigonometry – since I am notoriously bad at it. I’ve learned it about three times if I really have to use it, but for some reason as soon as I stop using it, it quite quickly drops from my mind again. I don’t doubt I’ll be getting reactions of math lovers who will point out this a stupid way to do it ;-). But this works, and that’s fine with me. Finally, the IsVisible property can be used to determine if the objects is on the screen at all.

The actual behavior

This behavior heavily leans on things I wrote about earlier, namely the extension methods for FrameWorkElement I described in my article  “Simple Windows Phone 7 / Silverlight drag/flick behavior” but which are now fortunately all in the Wp7nl library. It is also based upon the Safe event detachment ‘pattern’ for behaviors. Anyway – the base setup is like this:

using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Media;
using ARCompass.Behaviors;
using Phone7.Fx.Preview;
using Wp7nl.Utilities;

namespace HeadsUpCompass.Behaviors
{
  public class CompassDirectionDisplayBehavior : Behavior<FrameworkElement>
  {
    private FrameworkElement elementToAnimate;

    private FrameworkElement displayCanvas;

    private LocationCalcutator calculator;

    #region Setup
    protected override void OnAttached()
    {
      base.OnAttached();
      AssociatedObject.Loaded += AssociatedObjectLoaded;
      AssociatedObject.Unloaded += AssociatedObjectUnloaded;
    }

    void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
    {
      calculator = new LocationCalcutator 
        {DisplayCompassDirection = DisplayCompassDirection};
      elementToAnimate = AssociatedObject.GetElementToAnimate();
      if (!(elementToAnimate.RenderTransform is CompositeTransform))
      {
        elementToAnimate.RenderTransform = new CompositeTransform();
      }
      displayCanvas = elementToAnimate.GetVisualParent();
      if (displayCanvas != null)
      {
        displayCanvas.SizeChanged += DisplayCanvasSizeChanged;
        UpdateCalculator();
      }
    }
    #endregion

    #region Cleanup
    private bool isCleanedUp;

    private void Cleanup()
    {
      if (!isCleanedUp)
      {
        isCleanedUp = true;
        AssociatedObject.Loaded -= AssociatedObjectLoaded;
        AssociatedObject.Unloaded -= AssociatedObjectUnloaded;
      }
    }

    protected override void OnDetaching()
    {
      Cleanup();
      base.OnDetaching();
    }

    void AssociatedObjectUnloaded(object sender, RoutedEventArgs e)
    {
      Cleanup();
    }
    #endregion
  }
}

Now that most of the calculation logic is in the LocationCalculator, the calculation and positioning logic is reduced to these three little methods:

void DisplayCanvasSizeChanged(object sender, SizeChangedEventArgs e)
{
  UpdateCalculator();
}

private void UpdateCalculator()
{
  calculator.CanvasHeight = displayCanvas.ActualHeight;
  calculator.CanvasWidth = displayCanvas.ActualWidth;
  calculator.SetHorizontalPixels(6 * calculator.CanvasWidth);
  UpdateScreenLocation();
}

void UpdateScreenLocation()
{
  var translationPoint = 
     calculator.CalculateScreenPosition(CurrentCompassDirection);
  if (calculator.IsVisible(translationPoint))
  {
    elementToAnimate.SetTranslatePoint(
      calculator.CalculateScreenPosition(CurrentCompassDirection));
    elementToAnimate.Visibility = Visibility.Visible;
  }
  else
  {
    elementToAnimate.Visibility = Visibility.Collapsed;
  }
}

The fun thing is that the calculator’s resolution is set to 6 times the canvas width, so that every time you rotate the phone it recalculates the location where objects are displayed. The net result is that objects are spaced wider apart when you rotate the phone in landscape. Thus, the app makes optimal use of the screen space available.

And all there is left are two dependency properties: DisplayCompassDirection which holds the location in which the current object wants to be displayed, and CurrentCompassDirection  which should get the current direction the camera is looking at. By nature they are pretty verbose unfortunately:

#region DisplayCompassDirection
public const string DisplayCompassDirectionPropertyName = 
   "DisplayCompassDirection";

public int DisplayCompassDirection
{
  get { return (int)GetValue(DisplayCompassDirectionProperty); }
  set { SetValue(DisplayCompassDirectionProperty, value); }
}

public static readonly DependencyProperty DisplayCompassDirectionProperty = 
  DependencyProperty.Register(
    DisplayCompassDirectionPropertyName,
    typeof(int),
    typeof(CompassDirectionDisplayBehavior),
    new PropertyMetadata(0, null));
#endregion

#region CurrentCompassDirection
public const string CurrentCompassDirectionPropertyName = 
  "CurrentCompassDirection";

public int CurrentCompassDirection
{
  get { return (int)GetValue(CurrentCompassDirectionProperty); }
  set { SetValue(CurrentCompassDirectionProperty, value); }
}

public static readonly DependencyProperty CurrentCompassDirectionProperty =
  DependencyProperty.Register(
    CurrentCompassDirectionPropertyName,
    typeof(int),
    typeof(CompassDirectionDisplayBehavior),
    new PropertyMetadata(0, CurrentCompassDirectionChanged));

public static void CurrentCompassDirectionChanged(
  DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  var behavior = d as CompassDirectionDisplayBehavior;
  if (behavior != null)
  {
    behavior.UpdateScreenLocation();
  }
}
#endregion

Save and compile the app. Don’t run it yet.

DragBehaviorAdding/configuring the behavior using Expression Blend

Go back to Expression Blend, and use the following workflow:

  • In the Objects and Timeline Panel to the left, select ItemsControl “CompassItems”
  • Right-click on in, select “Edit Additional Templates”, then “Edit Generated Items (ItemsTemplate)”,  and finally “Edit Current”
  • Top left, select the “Assets” tab. In the left panel below it, select “Behaviors”. In the right panel you should see “CompassDirectionDisplayBehavior” appear.
  • Drag the behavior on top of the grid

As soon as you have done this, you will get a properties tab on the right of your screen that neatly shows the two dependency properties. Of course you can do this in code, but Blend takes care of creating namespaces and name space references – it makes life so much easier and that should appeal to a programmer’s natural laziness. Next task is data binding properties of the behavior to the ViewModel, and using Blend that is dead easy too.

Configuring behavior binding

behaviorpropertiesData binding to a behavior, yes sir (or ma’am)! Welcome to Mango: this is Silverlight 4, so no more complex hooplah with attached dependency properties if you want to have a behavior to play along with data binding. You can now directly bind to dependency properties in the behavior itself! After you have dragged the CompassDirectionDisplayBehavior on Grid, you get the little properties tab as displayed on the left, showing the behavior's two properties. To data bind these, use the following workflow:

  • Click the little square right of “DisplayCompassDirection” (indicated with the red circle), and select “Data Binding” from the popup menu
  • Choose tab “Data context” on the dialog that pops us (usually that’s default)
  • Select property “Direction : (Int32), that is directly under CompassDirections : (CompassDirectionModel)

You have now selected the DisplayCompassDirection property of the behavior to be bound directly to the “Direction” property to the CompassDirectionModel. One can argue if it’s technically corrDataBindingDisplayDirectionect to directly bind a Model in stead of having a ViewModel sitting in between. Since this Model only shows data and has no intelligence at all, I feel comfortable with it – if you do not, go ahead and define a ViewModel around it ;-)

The second and last part of binding goes like this:

  • Click the square behind “CurrentCompassDirection” and select “Data Binding” again in the popup menu
  • Select the “Data Field” tab
  • In the Data Field Tab, select “CompassViewModelDataSource” in the right pane
  • In the left pane, select “CompassDirection : (Int32)
  • Click the down-pointing arrow on the bottom of the dialog – more options appear
  • Select “TwoWay” for “Binding Direction”

You have now selected the CurrentCompassDirection property of the behavior to be bound to the CompassDirection of the CompassViewModel. And that means – you are done! Hit File/Save all and go back to Visual Studio to launch the application on your phone, and you will see compass directions moving through your screen if you move phone.

One for the road

Having a plain black screen to see the compass directions moving over is quite boring. So lets add the behavior to show the Windows Phone 7 camera as background I wrote some time ago as well. Add it to the project, drag it on top of the LayoutRoot grid, and bang – now you don’t only have a heads-up, but a see-trough compass as well!

Some final words

This is all pretty crude in terms of how things move, and there are quite some things eligible for improvement but nevertheless - what we have here is almost like any other old LOB MVVM based application. Business objects bound to the GUI. Only, that GUI happens to be an ItemsControl with a behavior on its template. Which turns the whole app into a dynamic experience. I hope to have tickled your imagination, and showed some useful Blend how-to as well.

MVVM is not limited to just LOB apps. Make something fun. To quote Nokia – make the amazing everyday ;-

Complete sample solution can be found here.

06 November 2011

Carpe Lumia!

Last updated November 10 2011

You know that band you used to love when you were in your teens? They really rocked your adolescent years. They rocked like hell. Their concerts where one great party. I would never end. ….except you grew up, the times changed, so did the music, but the band stuck to what made them great. Fame faded, and slowly they disappeared from your sight. Maybe even their CD’s did not make it into your MP3 collection. They lost their mojo. Sometimes they still performed, but you did not know and even less cared. Sic transit gloria mundi. We all have such a band. If you ask politely and promise to keep it a secret, I’ll tell you mine ;-) .

Now suppose, just for the sake of this analogy, after years and years this band of yours got back together. Not to do a ‘one more time for old times’ sake or a Live Aid gig, no: they kick out the drug-addicted drummer, recruit two new young guitar players, a few cool babes as extra singers, and team up with a new song writer. They reinvent themselves, make a new album – totally different music than what they did before, but still keeping what made them great – a beautiful performance. They bring out their new album and they TOTALLY rock the charts.

Now if you try to imagine the WTF feeling this would give you, you get an idea what I had for a few moments when I first booted up the Nokia Lumia 800 that was delivered on November 4. My first four mobile phones were all Nokia – and now this! Enough poetic mesmerizing, down to business. My thoughts on the Nokia Lumia 800. I’ll just follow the format I used for my HTC 7 Pro to make a fair comparison

The phone itself

It’s physical dimensions are 11.5 x 6 x 1 cm according to my own measurements, although I have to allow for a bit of uncertainty on the latter two because a cross-section on this phone would basically be an oval. The back side is convex, and so is the front side, i.e. the screen. This gives a very beautiful result. It weights 142 grams, which I don’t think is very much but it feels heavy – although I think solid would be a better way to describe it. The first thing that strikes – this phone is different from what I am used to in the Windows Phone arena. It’s beautiful. It has a smooth, streamlined look. And it feels that way, too. Its polycarbonate unibody design feels soft and it has nothing of this plasticy feel so common for these kind of devices. The hardware buttons are freakin’ made of metal – having used the Lumia for only a short time makes the camera button of the HTC 7 Pro feel like a wobbly piece of plastic on a cheap bubble contact. See below how this looks. Click for larger picture – as with all pictures in this post

Lumina2

The USB port is on the top, which I initially thought was very stupid for in-car use. When I attach a charger the plug would stick out of the top of the phone. Turned out I had not thought long enough about it. More about that later.

Screen

Lumia1Apparently Nokia have used some kind of AMOLED that is not the same as Samsung’s Super AMOLED. Nokia’s take on this is called “ClearBlack”. Black is very black, even seen from an extreme angle. Combined with the Nokia-only accent color “Nokia Blue” this gives a very beautiful, lively and crisp image on the start screen. The red is really like very burning fiery red. I don’t know if Omnia 7 users would be as impressed as I am, but coming from the considerably blander looking HTC screens this is nothing short of stunning. The tiles look like they are floating on the screen. Second thing that strikes is the device’s speed. There is a very notable performance increase compared to the HTC 7 Pro. Think Nodo-to-Mango faster. Things are happening at an uncanny speed. New messages in the People Hub are loaded like almost instantly. I suppose this is the faster processor doing its thing.

Another thing about the screen – it is very sensitive. So much actually that I had a little trouble getting the hang of it – I accidently kept selecting messages in the People hub when I just wanted to scroll trough them. But this extreme sensitivity has a rather unexpected bonus for me – combined the convex screen and the enhanced Mango keyboard I can actually touch type on it. I only managed this with the HTC Titan before – because that is simply big enough to accommodate my big carpenter’s son hands.

I am told the screen is made out of gorilla glass. This is supposed to be pretty scratch resistant. I did not try any destructive tests on it. I will report later on its durability.

Phone calls

Made one phone call with my wife. She said I sounded very crisp and and it was better than the HTC 7 Pro. Hello world, welcome to the smartphone that is actually able to make decent phone calls. Well phooey, is anyone impressed? Nokia were already making phones when I was just coming from college so if they had not figured out how to do this after all this time, they had best started making rubber boots again a long time ago.

The camera

WP_000006The first thing that struck me about the camera is that there’s a lot more options in the camera menu than I was used to, like Contrast, Saturation, Focus Mode, ISO, Exposure Mode and White Balance. I took this pretty autumn scene picture with it and I think that looks pretty good. Like I said in my review of the HTC 7 Pro, I am a photographer too and if I take pictures I care about I use a Canon EOS 400 DSLR, so in my book pictures taken by any mobile phone are all, well, let’s keep this polite ;-). Having said that: if I zoom in on pictures made by my HTC 7 Pro I can zoom in about twice before things start to become grainy. Lumia 800: seven times. Nokia wins this hands-down. But that’s from my old phone. I have no comparison with other new phones. I have heard quite mixed results from this.

I also took a few pictures of flowers close by but that did not work out at all. Only later I found out that this probably has to do with the default Focus mode – that’s Macro, and then apparently it does not want to focus on things close by.

Sound

Lumia3I think the best way to describe the sound that comes out of that tiny little speaker on the bottom is something among the lines of “HOLY C…!!!”. I played my little game of Catch’em Birds. When you slam a bird into a cage, it gives a kind of metallic clang, trying to convey the idea of a metal cage door closing behind the bird. On the Lumia 800 this actually sounds more like a vault slamming shut. This device makes a pretty decent stand alone music player. Which has a flip side, too – I played Hydro Thunder Go on it and, well, er, the excellent speaker mercilessly reveals the game sounds effects are actually pretty low quality. But I can hardly blame Nokia for that ;-)

Miscellaneous

Lumia4The nice blue box it comes in contains the standard equipment, i.e. an USB charger with detachable cable (so it can be used to connect the phone to Zune as well), a pair of headphones, a box of manuals in various languages (still unread *cough*) and a silicon case. It actually fits like a glove, and is in the same color as the phone’s body. I suppose it’s for protecting the phone’s shell, but it eludes me from what exactly, since the phone itself is made from a material used in the helmets ice hockey players wear. My wife suggested it was for preventing the floor tiles to crack when you drop a Lumia 800 on it ;-). I also heard these cases will come in different colors, and if that is the case I am so much going to get a blue one ;-). [Note: the blueish reflection of the screen is a side effect of the flash, you don't see this in real life - I just wanted to emphasize the silicon case]

The headphones are kinda cheap and don’t to the phone’s music playing capabilities much justice. For those who want better sound quality, Nokia makes these amazing Monster headsets that are a much better match for the phone.

Software and extra’s

No review of a Lumia 800 would be complete without the on-board extra’s. First of all – we got the genuine iconic, nay, legendary Nokia ringtone and SMS alert. Played on a xylophone. Very nice. For now I selected all the Nokia sounds as a default, just for the heck of it.

Then we have Nokia Drive. Say hello to free turn-by-turn navigation with downloadable maps and voice directions. I don’t know if it’s actually completely world wide, but if I select Manage Maps/Install, I first have to select which continent I want maps to install for: Africa, America, Asia, Australia/Oceania and Europe. Drilling down reveals Russia is in there. China is in there. South America is in there too - including Argentina which does not even have a Marketplace, and the Cayman Islands for heavens’ sake. If works way better than Bing Maps directions, and it’s free! And what’s even better – it supports landscape mode, so you can turn your phone sideways and have wide angle navigation. And then the penny dropped – maybe this is why the USB port is on top, for if you use it for navigation you rotate it 90° and then the USB port is conveniently pointing sideways for the car charger.

The current version of Nokia Drive still needs an online connection for finding addresses and Points of Interest, but at the Tweakers event at November 9 in Amsterdam Nokia revealed an update that supports total offline navigation will be available very soon. So I guess it's time to kiss my old TomTom goodbye. The Germans have a very good saying about this, attributed to Mikhail Gorbachev: “Wer zu spät kommt, den bestraft das Leben” (life punishes those who are too late)

Nokia Maps – can’t say much about this; what I currently have on my phone is a very early beta that is obviously not ready yet, but it seems to be a non-driver’s map application for finding your way around. You know? Like Local Scout, but one that does work in Europe? As a GIS developer I very much wonder if this can be extended and used like the Bing maps control in custom applications. I am not sure if this will eventually work completely offline as well.

Nokia Music – reminds me of what I saw from Pandora before us Europeans got kicked out. Stream music from a multitude of pre-defined ‘stations’ and you can buy and download stuff from Nokia’s MP3 store if you like. Yesterday I just turned it on “80’s rock” and let it go for hours on end. You can skip a limited number of songs you don’t like. The price of listening: zilch. Nada. Nothing. No pass required, no subscription required. Booya Nokia! Does this compete with Zune? Like hell it does – if we could get Zune here. Zune is available in like, 8 countries? Nokia music in a little short of 40, if I am correct. In the mean time – this is great news for all people outside the Zune coverage area. But beware – this eats a lot of data. Don’t run this over your 3G connection unless your unlimited plan is really unlimited. The software specifically warns you for that on first startup.

Room for improvement

Nokia have gone out on a limb to make the ultimate Windows Phone 7 and I think they came pretty far – but there is still room for improvement. From a hardware standpoint, it lacks two features, which by now everyone has heard of:

  • No front facing camera
  • No gyro

Now the gyro is a feature that the proverbial Iowa soccer mom ain’t  gonna miss – the camera is going to hurt if indeed Skype comes to Windows Phone 7. Although I also wonder how much it will actually hurt – I’ve had a video call capable phone for 2.5 years and only used this feature it 3 times – to demo it. I have no idea how much iPhone users actually use FaceTime all the time.

I think Nokia could also look into bringing out a model with more storage aboard. It now ‘only’ has 16GB of storage, which is more than enough for my podcasts, photo’s and music (I may be just weird but I don’t go carrying around enormous music libraries) but apparently there are people need more these days.

Personally I would like also like to have seen a somewhat larger screen.

The verdict

I shelled out €562 to get a Windows Phone 7 with keyboard from the UK to the Netherlands only 8 months ago. I am a die hard physical keyboard phone user. After playing with the Nokia Lumia 800 for only 48 hours, I transferred all my stuff to it and shut down the HTC 7 Pro. Sorry old workhorse. You did well. I know I am going to miss the keyboard sometimes, but the screen colors, the relative sluggish response, the already battered plastic shell, the ablating battery case… it’s just no match for this design beastie.

If you want a phone that supports all the latest Windows Phone 7 hardware features, buy something else. There is plenty of choice. That’s the fun thing of Windows Phone 7 – there is a baseline quality, they’re basically all good, and you do have a choice. One size does not fit all – as for instance the HTC Titan shows quite literally. If you want a really well designed, durable and smart looking, and not overly large Windows Phone 7 device with some very nice free extra’s that’s available at a pretty aggressive price point, by all means, buy the Lumia 800. Especially the blue one. I predict that is going to be a phone you can put on the table and everyone will know what it is – pretty soon.

Concluding thoughts

If this is what Nokia can crank out in 8 months, I really wonder what will happen in 2012. But even more important than what they crank out, is how they do it. They really got their marketing act together, and it looks like we are finally going to see some serious marketing for the Windows Phone 7 environment. I see posters, dummy’s and demo models of actual Windows Phone 7 devices appearing in shops. Someone from the #wp7nl gang who has a Lumia too walked into a Vodafone shop to get a microsim and the staff all recognized the phone immediately.

The time for Windows Phone 7 being an ‘underground’ phone platform is over!

30 October 2011

So what about Windows Phone 7 adoption rates?

“There are three kinds of lies: lies, damned lies and statistics” (Benjamin Disraeli)

There is a nifty little Windows Phone 7 app out there called “…I’m a WP7”, made by a person who calls himself “Liquid Daffodil”. It’s a bit hard to describe what its actual purpose is. It’s got a lot of features: it can show other people using the same app nearby on a map or a list, it’s got a forum in it, you can send messages to each other, you can see who is developer (or claims to be) and who is not, you can see Xbox avatars, it’s got news about Windows Phone, it also shows you in which ‘hive’ you are (I still don’t quite get that) – anyway, if I may name a main purpose it seems to be you can proudly flag you are a Windows Phone 7 user – but only to other Windows Phone users running the same app. Its subtitle is “join the movement”.

That may not sound very useful but there is this one thing – it’s got a little option called “statistics”. It shows how much people are using this app, both worldwide and in your country, and how much are claiming to be developers. I’ve been tracking these statistics for the last 14 days and ended up with the following results:

image

image

Left axis shows number of users, right axis number of people who claim to be developers.

I only show these numbers, and I leave interpretation to the reader’s responsibility and wisdom. I would like to point out these are the usage rates of a single app over 14 days, from an unverifiable source (which, if they are true, I am very jealous of). There are some oddities in it, like the number of Dutch users claiming to be developer actually dropping and then sharply rising. I show them anyway, if only to show that I am not only sharing things I would like to see. But I would also like to point out that apparently, in only 14 days worldwide usage of this app rose with a staggering 23%, the number of people claiming to be developers worldwide with 18%. For the Netherlands the numbers are 25% and 13%.

So what does this say about the actual adoption rate of Windows Phone 7 as a whole, as I so provocatively called this article? Well, basically nothing at all. How hard is this data? How many % of the total users and developers are actually running this App? How reliable is the developer’s tracking system? Is he telling the truth at all? I can only speculate, and on speculation I got a very good advice from a fellow MVP whose words I tend to take for wisdom, which basically was: “don’t speculate”. It only shows that there seems to be growth – and quite substantial growth, too. If this bears any kind of correlation with the actual growth of the Windows Phone 7 as a platform life will be interesting indeed :-)

It shows another thing: I really s*ck at making Excel charts. My sincere apologies ;-)

For the record, I wish to state that I have not been given insight in any actual Windows Phone 7 usage data. Microsoft is not telling these things, not even to a Phone Development MVP. As to why this is, once again one can only speculate, which I was advised not to do, so I don’t. I just used publicly available data.

21 October 2011

Using the motion API to check what direction the camera is looking

Recently I had my very first real try with the Windows Phone 7 Motion API, using the Simple Motion Sample and the Augmented Reality Motion Sample which both can be found here. Especially the motion API gave results that I found initially very puzzling. My idea was to find out where direction in which the camera is pointing – regardless of how the user holds his phone. Life then becomes pretty interesting. As long a you hold your phone in the standard upright portrait direction, things are pretty simple – Yaw direction is more or less the negative of compass direction – as far as the direction in which the camera is looking is concerned. But if the user holds his phone upside down or in landscape mode, you have to account for the fact that although the camera is pointing in the same direction, the top of the phone is pointing in another direction!

I found the following line of reasoning to be fairly correct:

  • If Roll is around –90 degrees, the user is holding his phone in landscape mode with the phone top to the left. This is similar to PageOrientation.LandscapeLeft. Compass direction = 360 - yaw + 90 degrees.
  • If Roll is around 90 degrees the user is holding his phone in landscape mode with the phone top the right. This is similar to PageOrientation.LandscapeRight. Compass direction = 360 – yaw - 90.
  • If Pitch is about 90 degrees and Roll around 0, the user is holding the phone in portrait mode and upright. This is similar to PageOrientation.PortraitUp. Compass direction =  -yaw.
  • If Pitch is about -90 degrees and Roll about 0, then the user is holding the phone in portrait mode and upside down. This is similar to PageOrientation.PortraitDown.
    Compass direction = 360 - yaw + 180.

In code I translated this as follows:

public int GetCameraViewDirection(SensorReadingEventArgs e)
{
  var yaw = MathHelper.ToDegrees(e.SensorReading.Attitude.Yaw);
  var roll = MathHelper.ToDegrees(e.SensorReading.Attitude.Roll);
  var pitch = MathHelper.ToDegrees(e.SensorReading.Attitude.Pitch);

  if (roll < -20 && roll > -160)
  {
    return Normalize(360 - yaw + 90);
  }
  else if (roll > 20 && roll < 160)
  {
    return Normalize(360 - yaw - 90);
  }
  else if (pitch > 20 && pitch < 160)
  {
    return Normalize(-yaw );
  }
  else if (pitch < -20 && pitch > -160)
  {
    return Normalize(360 - yaw + 180);
  }
  
  // No sensible data
  return -1; 
}

private int Normalize( int compassDirection )
{      
  if (compassDirection > 360)
  {
    compassDirection -= 360;
  }
  if (compassDirection < 0)
  {
    compassDirection += 360;
  }
  return compassDirection;
}

The MathHelper, by the way, comes from Microsoft.Xna.Framework. If you don’t like my ‘easy way out’ way of returning –1, throw an exception if you like. The Normalize function always makes sure the result is always between 0 and 360 degrees.

There are some interesting considerations. For example, if you can trap the “OnPageOrientationChanged” event and check it’s value, why then even check pitch and roll? Well, one important reason is that PageOrientation.PortraitDown for some reason is not supported. Try it – use any App supporting Landscape and Portrait. Hold your phone in portrait mode upside (i.e. with the phone top pointing to the floor… nothing happens).

I also noticed that in the first two cases any value coming from Pitch can best be ignored, because it varies wildly on my phone.

17 October 2011

A behavior to show the Windows Phone 7 camera as background

This article was updated October 29, 2011, implementing correctly handling of “back” navigation

In a previous post I showed how to use the camera feed as background on a page of a Windows Phone 7 application. Today, I make it even easier for the really really lazy programmer: I have created a behavior to do the same. As a bonus, this behavior also takes the page orientation into account and whether the SystemTray is visible or not.

First order of business: make a basic behavior. Using the snippet from my previous safe event detachment pattern for behaviors the initial setup looks like this:

namespace Wp7nl.Behaviors
{
  /// <summary>
  /// A behavior that shows a camera view on the background of a panel
  /// </summary>
  public class CameraViewBackgroundBehavior : Behavior<Panel>
  {
    private PhotoCamera camera;
    private PhoneApplicationFrame parentPage;
    private Uri pageSource;
    private VideoBrush backgroundBrush;

    // Setup and cleanup according to http://bit.ly/dZb6D9

    #region Setup
    protected override void OnAttached()
    {
      base.OnAttached();
      AssociatedObject.Loaded += AssociatedObjectLoaded;
      AssociatedObject.Unloaded += AssociatedObjectUnloaded;
    }

    private void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
    {
      DoInit();
    }
    #endregion

    #region Cleanup
    private bool isCleanedUp;

    private void Cleanup()
    {
      if (!isCleanedUp)
      {
        isCleanedUp = true;
        AssociatedObject.Loaded -= AssociatedObjectLoaded;
        AssociatedObject.Unloaded -= AssociatedObjectUnloaded;
        DoCleanup();
      }
    }

    protected override void OnDetaching()
    {
      Cleanup();
      base.OnDetaching();
    }

    private void AssociatedObjectUnloaded(object sender, RoutedEventArgs e)
    {
      Cleanup();
    }
    #endregion
  }
}
With sincere apologies to region haters ;-). Nothing special here, just a skeleton behavior on a Panel. From the AssociatedObjectLoaded a method "DoInit" is called, which does actually all that’s needed to get this behavior going:
/// <summary>
/// Initializes the behavior
/// </summary>
private void DoInit()
{
  // Find the page this control is on and listen to its orientation changed events
  if( parentPage == null)
  {
    parentPage = Application.Current.RootVisual as PhoneApplicationFrame;
    pageSource = parentPage.CurrentSource;
    parentPage.Navigated += ParentPageNavigated;
  }  
  parentPage.OrientationChanged += ParentPageOrientationChanged;

  camera = new PhotoCamera();

  // Create a video brush with the right parameters
  backgroundBrush = new VideoBrush();
  backgroundBrush.Stretch = Stretch.UniformToFill;
  backgroundBrush.AlignmentX = AlignmentX.Left;
  backgroundBrush.AlignmentY = AlignmentY.Top;

  // Set the video brush to the background of the panel 
  // and do an initial display
  AssociatedObject.Background = backgroundBrush;
  backgroundBrush.SetSource(camera);
  SetVideoOrientation(parentPage.Orientation);
}

The comments in the source show pretty much what it does: it starts listening to page orientation change events, it sets up the video brush (but now from code in stead of from XAML) and sets the brush to the background of the panel.

Of course, it has its counterpart disabling all settings again:

/// <summary>
/// Safely detach all extra events
/// </summary>
private void DoCleanup()
{
  parentPage.OrientationChanged -= ParentPageOrientationChanged;
  camera.Dispose();
}

To make sure the behavior initializes correctly again when the user navigates back to the page with this behavior on it, the following code is needed (and this is the part I missed myself in the first version of this post)

/// <summary>
/// Re-init when user navigates back to this page
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ParentPageNavigated(object sender, NavigationEventArgs e)
{
  if (e.NavigationMode == NavigationMode.Back && e.Uri.Equals(pageSource))
  {
    isCleanedUp = false;
    AssociatedObject.Loaded += AssociatedObjectLoaded;
    AssociatedObject.Unloaded += AssociatedObjectUnloaded;
  }
}

I appears a behavior’s OnAttached is not called when a user navigates back to a page, resulting in the video not being displayed on the background. Anyway, to wrap up the code, you simply need this:

private void ParentPageOrientationChanged(object sender, 
                                          OrientationChangedEventArgs e)
{
  SetVideoOrientation(e.Orientation);
}

/// <summary>
/// Sets background video brush parameters based upon page orientation
/// </summary>
/// <param name="orientation"></param>
private void SetVideoOrientation(PageOrientation orientation)
{
  System.Diagnostics.Debug.WriteLine("Switching to {0}", orientation);
  switch (orientation)
  {
  case PageOrientation.PortraitUp:
    backgroundBrush.Transform = 
      new CompositeTransform { Rotation = 90, TranslateX = 480 };
    break;
  case PageOrientation.LandscapeLeft:
    backgroundBrush.Transform = null;
    break;
  case PageOrientation.LandscapeRight:
    if (Microsoft.Phone.Shell.SystemTray.IsVisible)
    {
    backgroundBrush.Transform = 
      new CompositeTransform { Rotation = 180, TranslateX = 728, TranslateY = 480 };
    }
    else
    {
    backgroundBrush.Transform = 
      new CompositeTransform { Rotation = 180, TranslateX = 800, TranslateY = 480 };
    }
    break;
  }
}

Based upon the way the page is oriented, a different translation and/or rotation is applied. The number are easy enough to recognize, 800 being the vertical resolution and 480 the horizontal resolution of a Windows Phone 7 screen. Apparently a system tray takes about 62 pixels – at least, that was the value I got by trial-and-error till the camera view filled the whole screen background. Bear in mind that although this will probably work on any panel, the numbers only make sense if you add this behavior to it’s top panel.

Now its simply a matter of dragging this behavior on top of your top panel using expression Blend, and boom – instant camera background. No coding necessary, and a clean and empty code behind file. You big coder hero makes friends with designer ;-)

Code file can be downloaded here. I will soon add this to the wp7nl library on codeplex

08 October 2011

Taking screenshots with Windows Phone 7 applications using a video feed

The Marketplace screenshot tool that came with the Windows Phone 7.1 SDK made life for developers a whole lot easier. But suppose you want to enable users to make screenshots from their application in action? This article shows you how.

First of all, the easy part. The framework allows you to make a screen capture by making a WriteableBitmap from a user interface element in a pretty simple way. Create a new Windows Phone application, and select framework version 7.1. Then add a reference to Microsoft.Xna.Framework.dll. Enter the following XAML in your MainPage.xaml

<Grid x:Name="LayoutRoot">
  <Grid>
    <Grid.Background>
      <ImageBrush x:Name="BackgroundImageBrush"
      Stretch="UniformToFill" ImageSource="ScreenBackground.jpg" 
   AlignmentX="Left" AlignmentY="Top"/>
    </Grid.Background>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <!--TitlePanel contains the name of the application and page title-->
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
      <TextBlock x:Name="ApplicationTitle" Text="SCREENSHOOTER" 
   Style="{StaticResource PhoneTextNormalStyle}" 
          DoubleTap="ApplicationTitle_DoubleTap" Foreground="#FF0000" />
      <TextBlock x:Name="PageTitle" Text="hello world" Margin="9,-7,0,0" 
   Style="{StaticResource PhoneTextTitle1Style}" Foreground="#FF0000" />
    </StackPanel>

    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
      <TextBlock Height="223" HorizontalAlignment="Left" Margin="52,169,0,0" 
   Foreground="#FF0000" 
          Text="Planeth Earth is blue and there's nothing I can do" 
   VerticalAlignment="Top" FontSize="48" TextWrapping="Wrap" />
    </Grid>
  </Grid>
</Grid>

A pretty basic page with all texts in bright red and a background picture; this sample uses the background of Map Mania, about half of the globe as seen from space, but you can just use any 480x800 image. Then add just a little code to the MainPage.xaml.cs:

private void ApplicationTitle_DoubleTap(object sender, GestureEventArgs e)
{
  TakeScreenShot();
}

private void TakeScreenShot()
{
  // Take a screenshot 
  var screenshot = new WriteableBitmap(this, null);
  var screenshotname = String.Format("Screenshooter_{0}", DateTime.Now.Ticks);
  using (var ms = new MemoryStream())
  {
  screenshot.SaveJpeg(ms, 480, 800, 0, 85);
  ms.Seek(0, SeekOrigin.Begin);

  var library = new MediaLibrary();
  var pic = library.SavePicture(screenshotname, ms);
  }

  MessageBox.Show(string.Concat("Screenshot saved as ", screenshotname));
}

Screenshooter_634536668888930000This is your basic screenshooter. Double-tap the header and it makes a WriteableBitmap of the entire screen, saves it as a JPEG on a MemoryStream, and writes the result into a picture in the media library. The result looks something like displayed here on the right.

Once again this shows how simple things can be created in Windows Phone 7. But although this application has some merits – for instance, to allow users of your App to create screenshots ‘in the field’, from a game situation or something like that – it’s pretty limited. Let’s make things a little bit more livelily and replace the static image by something more interesting – a live camera feed!

This was already described earlier in this blog, and applying the same technique, update the top part of the XAML a little:

<Grid x:Name="LayoutRoot">
    <Grid.Background>
      <VideoBrush x:Name="BackgroundVideoBrush"
          Stretch="UniformToFill" AlignmentX="Left" AlignmentY="Top">
          <VideoBrush.Transform>
            <CompositeTransform Rotation="90" TranslateX="477"/>
          </VideoBrush.Transform>
      </VideoBrush>
    </Grid.Background>
    <Grid>
      <Grid.Background>
        <ImageBrush x:Name="BackgroundImageBrush"
        Stretch="UniformToFill" Opacity="0" AlignmentX="Left" AlignmentY="Top">
          <ImageBrush.Transform>
            <CompositeTransform Rotation="90" TranslateX="477"/>
          </ImageBrush.Transform>
        </ImageBrush>
      </Grid.Background>

The rest of the XAML is unchanged. Notice the ImageBrush stays – its Opacity is set to 0, it’s ImageSource tag is now empty and it gets the same transform applied to as the video brush. Why it’s not simply removed will become clear in a moment. Add a little code to the MainPage.xaml.cs

PhotoCamera cam;

protected override void OnNavigatedTo(NavigationEventArgs e)
{
  base.OnNavigatedTo(e);
  cam = new PhotoCamera();
  BackgroundVideoBrush.SetSource(cam);
}

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
  base.OnNavigatedFrom(e);
  cam.Dispose();
}

Screenshooter_634536134540840000Running this app on the phone will show the live camera feed displayed as a background and the texts floating over it. Double-tap the header again, and the result is …

…not what you might expect, or at least not what you had hoped. The video feed is not being captured. To get this done, a little more trickery is needed. First, add two more methods to the MainPage.xaml.cs:

 

 

 

private void PrepareScreenShot()
{
  // Create capture buffer.
  var ARGBPx = new int[(int)cam.PreviewResolution.Width * 
                  (int)cam.PreviewResolution.Height];

  // Copies the current viewfinder frame into a buffer.
  cam.GetPreviewBufferArgb32(ARGBPx);

  // Copy to preview image into a writable bitmap.
  var wb = new WriteableBitmap((int)cam.PreviewResolution.Width, 
                               (int)cam.PreviewResolution.Height);
  ARGBPx.CopyTo(wb.Pixels, 0);
  wb.Invalidate();

  // Display that on the screen
  BackgroundImageBrush.ImageSource = wb;
  BackgroundImageBrush.Opacity = 1;
}

private void ContinueVideo()
{
  BackgroundImageBrush.Opacity = 0;
  BackgroundImageBrush.ImageSource = null;
}

Screenshooter_634536149331290000Then, add a call to “PrepareScreenShot” at the top of “TakeScreenShot”, and a call to “ContinueVideo” at the bottom of it. What this basically does is copy the viewfinder preview data into a buffer, make a WriteableBitmap of that, feed that to the as of yet transparent BackgroundImageBrush overlaying the video, and make that brush visible. Then, you have essentially a video-still beneath your texts and that will get screencaptured, as showed to the right – I took a picture of my monitor showing the code of the solution. After the screenshot is saved, BackgroundImageBrush is cleared and made transparent again -and the video feed becomes visible again, ready for the next shot.

One last thing to add: by this time you may have noticed that double-tapping the screen is not the best way to take a picture – they tend go get a little blurry. That’s probably another reason why Microsoft made the camera button a mandatory Windows Phone feature, so lets use it. First, add a little code for processing the camera button events:

void CameraButtons_ShutterKeyHalfPressed(object sender, EventArgs e)
{
  if (cam.IsFocusSupported)
  {
    cam.Focus();
  }
}

void CameraButtons_ShutterKeyPressed(object sender, EventArgs e)
{
  TakeScreenShot();
}

This brings about another little detail: the camera can get be given a focus command, but apparently not all cameras support this, so first ask the camera if it supports focus at all. Finally, make sure the camera button events are attached and detached at the right moment, so adapt the OnNavigatedTo and OnNavigatedFrom methods like this:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
  base.OnNavigatedTo(e);
  cam = new PhotoCamera();
  CameraButtons.ShutterKeyPressed += CameraButtons_ShutterKeyPressed;
  CameraButtons.ShutterKeyHalfPressed += CameraButtons_ShutterKeyHalfPressed;
  BackgroundVideoBrush.SetSource(cam);
}

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
  base.OnNavigatedFrom(e);
  CameraButtons.ShutterKeyPressed -= CameraButtons_ShutterKeyPressed;
  CameraButtons.ShutterKeyHalfPressed -= CameraButtons_ShutterKeyHalfPressed;
  cam.Dispose();
}

And there you have it – a basic Augmented Reality Photo shooter.

All the credits go to Matthijs Hoekstra for laying the groundwork for this article with his Rhino Vision application - and supplying me with the full sources, so I only had to demolish refactor it into a basic understandable sample. I hope to see a boatload of ‘funny picture applications’ in the Marketplace soon.

You can find the full source of the ScreenShooter sample app here.