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.

05 October 2011

Wireless podcast sync on Windows Phone 7 outside USA–yes we can!

Sorry! No code here as well, but a usability tip.

Mango RTM came, the Dutch Marketplace went live, I nuked my HTC7 Pro and finally used my age-old live id as primary live id. I registered my credit card and bought my first apps. Now I knew in advance not all the cool features that were available when I still was running my fake live id based on a random ZIP code in Texas (I think) would still be there when I switched live id, but I was not prepared for was the fact that the whole podcast Marketplace part was missing. Fortunately there is a work-around for this: Zune downloads anything you know the RSS for. So if you want to listen to Windows Dev Podcast as I do every week, you just enter their RSS feed (http://feeds.feedburner.com/WindowsPhoneDevPodcast) and boom, Zune starts loading their podcasts.

But now I was back to downloading episodes via Zune again by attaching my phone to my computer. I was just getting used to letting the phone taking care of that – as soon as it was in Wi-Fi range of my home it started to check for new episodes and lo and behold, automagically Lowdermilk & Lowdermilk appeared on my phone, just as the DotNed podcast, Windows Phone Radio and more.

Turns out that once you have one episode downloaded on your phone via Zune, you can then start synching via Wi-Fi again. It’s dead simple.

  • Once you have synced a podcast episode over an USB cable via the Zune program to your phone, disconnect it
  • Open Zune on your phone
  • Tap “podcasts”
  • Tap the descriptive text of the podcast on the right, not the logo
  • You will get a list of downloaded episodes (default Zune downloads 3).
  • And a button “subscribe”

And then you are where you were before you lost the podcast Marketplace. Tap it, and you are basically done. From now on your phone will sync podcast episodes over Wi-Fi again. If this is by design or by accident, I don’t know, but it works.

03 October 2011

The Standard About Page for Windows Phone 7 revisited

Back to business!

Although section 5.6 requiring an application to have easily discoverable application name, version information, and technical support contact information is still in the Windows Phone 7 Application Certification Requirements, it is no longer strictly enforced as far as I know. Yet, it’s still a very good idea to include this. It allows your App’s buyers to quickly review and rate your App and moreover, contact you easily, and usually providing you with all kinds of free ideas to make your App even better. What is better than to get direct input from the very people who bought your App!

I wrote about a Standard About Page some time ago. The latest version is now included in the 2.0.1 version of my wp7nl library on codeplex, which is also available as a Nuget package. Apart from some minor improvements to the AboutViewModelBase (and the update to MVVMLight 4.0), by popular request I created a user control, or actually, multiple user controls.

If your reference the wp7nl library, you will get three “About” controls:

  • AboutContents
  • AboutData
  • AboutInfoSymbol

AboutData is the complete thing: create an empty page, delete everything within LayoutRoot Grid, drag this control in it, bind your AboutViewModelBase descendant, and you are ready. Apart from the namespace declarations, all that’s left of the contents of the About Page of my Map Mania App now looks like this:

<phone:PhoneApplicationPage.Resources>
  <Model:AboutViewModel x:Key="AboutViewModel"/>
</phone:PhoneApplicationPage.Resources>

<Controls:PhoneApplicationPage.Style>
  <StaticResource ResourceKey="PhoneAppStyle"/>
</Controls:ExtendedPhonePage.Style>
<Grid x:Name="LayoutRoot" Style="{StaticResource LayoutRootStyle}" 
   DataContext="{StaticResource AboutViewModel}">
  <Controls:AboutData/>
</Grid>

Again, by popular request this is built up out of of two sub controls, AboutContents (everthing below the actual “About”) and AboutSymbol (the info-symbol). A picture says more than a thousand words, therefore:

 About

This, for instance, allowed me to construct the About ‘page’ of Catch’em Birds as part of a Panorama view, using just the AboutSymbol and the Contents like this:

<controls:PanoramaItem x:Name="PanAbout" 
  Header="{Binding LocalizedResources.About, Source={StaticResource LocalizedStrings}}" 
  Margin="0,-1,0,0">
  <controls:PanoramaItem.HeaderTemplate>
    <DataTemplate>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="0.994*"/>
          <RowDefinition Height="0.006*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="40"/>
          <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <LocalJoost:AboutInfoSymbol HorizontalAlignment="Left" 
           VerticalAlignment="Bottom" Margin="0,0,0,6"/>
        <TextBlock Grid.Column="1" 
           Text="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}" 
           FontSize="64" Margin="0" Grid.RowSpan="2" />
      </Grid>
    </DataTemplate>
  </controls:PanoramaItem.HeaderTemplate>
  <LocalJoost:AboutContents Name="aboutContents1" 
    DataContext="{Binding Instance.AboutViewModel, Source={StaticResource MainViewModel}}" />
</controls:PanoramaItem>

about2

Which yields the result as displayed on the left.

So now you can create an About Page with even less effort. You still have to make a child class of AboutViewModelBase and a resource file as described in the first About Page post but that’s about all.

A sample implementation of the whole stuff can be found here.

Have fun!

02 October 2011

Being spammed to MVP

This posting is not about code or anything. Skip it if you are searching for that ;)

I had a rotten day yesterday. I was tired from an extremely busy and stressed-out working week, I slept badly, and I was developing a severe cold while it finally looked like nice weather here. I was visiting my mum – who was relating about the funeral of my niece the day before. She had passed away out of the blue at 46, just four years older than me. This made me ponder about my own future, my dad who passed away at 48 (when I was only 15), stuff like that. A cheerful mood indeed.

In the godforsaken town my mum lives there’s hardly wireless internet, so I saw two or three MVP renewals trickling in, but could hardly respond. Nor was I really in the mood for it. Next stop were my parents-in-law, who live in the same town a couple of blocks away (yeah so I married the Girl Next Door, sue me ;) ) for a family BBQ. Fortunately no sick or dead relatives talk here, but to compensate for that I had developed a splitting headache. Picture the scene? “One of those days”.

So while I was listlessly munching away some BBQ stuff I wanted to show my Windows Phone 7 to my Android-using brother in law (his Facebook App was broken again) and for some reason noticed a revolving live tile with a twitter message congratulating new and renewed MVP’s in general and if everyone else could please check their spam folder? So I connected to my father-in-laws Wi-Fi network (he’s a bit more up-to-date than my mum), and still not believing anything I let my phone sync my gmail spam folder and picked it up again 10 minutes later or so.

I almost dropped my phone and I suppose I made some kind of strangled sound. I don’t quite remember, I think a few neurons fused out that moment ;) - just that my wife looked at me with that special worried ‘what the hell is wrong with YOU?’ look. I just showed her my phone. It read:

Congratulations 2011 Microsoft MVP!

Congratulations! We are pleased to present you with the 2011 Microsoft® MVP Award! This award is given to exceptional technical community leaders who actively share their high quality, real world expertise with others. We appreciate your outstanding contributions in Windows Phone Development technical communities during the past year.

She passed it to the people present and they all started to congratulate me. Still not believing it, I managed to retrieve my phone and contacted our local Windows Phone 7 DPE Matthijs Hoekstra (using – how fitting – Windows Phone 7 Live Messenger integration, or maybe Facebook chat, I did not quite pay attention to that) to check if no-one was pulling a sick joke on me. He confirmed it was the real thing and he was already wondering why he did not hear anything from me – it was more than 2.5 hours since the mails got out.

I can assure you even Windows Phone 7 auto correction had a hard time with my trembling hands (sneezing in the process does not help either), but I finally managed to get out

twitter

… and then my phone nearly exploded with congratulations, it was just impossible to keep up with it and thank everyone in person. It’s a bit lame, but hereby: thank you all for your good wishes and congratulations. I especially thank my fellow developers from #wp7nl who have nominated me. I hope to prove being worthy of this honor.

Just remember this: I will not deny being very proud of this, but I am still just Joost. I am an ordinary developer just like you, who got enthusiastic about Windows Phone 7. I like to tinker, code, write (and write about code), help out other people who got stuck if I can, share ideas and knowledge, on a user or developer level. Just because I have fun doing that, and I learn a lot in the process of doing so, too. Apparently I did this in a way that pleased some people within Microsoft to such an extent that they decided to praise me in public this way. I appreciate this very much, but I never was, nor will I ever be, a divine oracle of Windows Phone 7. Nor have I transcended to some god-like being.

So please don’t approach me differently because ‘wow he’s now an MVP’ right? Still ‘just Joost’, who will help if he can.