26 September 2013

Utility classes to check if lines and/or rectangles intersect

I have a for a developer unusual confession to make: I don’t like math. As a tool, great, but as a thing, no. One thing that really infuriates me is than when you want something simple (like intersecting lines and rectangles) all you get is formulas. Even on StackOverflow. I want code. So whenever I translate something from formulas or another computer language, I take care to ‘give back’ the resulting code to prevent other people needing to do the same.

So when I needed a few lines of code to check if lines intersected with each other or with a rectangle – as I need to know when the ball moves over the screen of my Windows Phone app 2 Phone Pong, I was presented with the usual bunch of mathematical formulas… and finally some C code. Which I translated back to C#, so now every sod (like me) can check if a lines intersect with lines, or with a rectangle.

I am not even going to pretend to understand how this actually works, but it does. I have created a class LineF that you can create from two points, and that starts like this:

using System;
using System.Windows;

namespace Wp7nl.Utilities
{
  public class LineF
  {
    public double X1 { get; set; }
    public double Y1 { get; set; }
    public double X2 { get; set; }
    public double Y2 { get; set; }

    public LineF()
    {
    }

    public LineF(double x1, double y1, double x2, double y2)
    {
      X1 = x1;
      Y1 = y1;
      X2 = x2;
      Y2 = y2;
    }

    public LineF(Point from, Point to)
      : this(from.X, from.Y, to.X, to.Y)
    {
    }

    public Point From
    {
      get { return new Point(X1, Y1); }
    }

    public Point To
    {
      get { return new Point(X2, Y2); }
    }
  }
}
And added this method that gives you a Point if there are intersections, and null if there are not. The original method returned some structure that had a field that told you why there were no intersections, but I could not care less about that, so I simplified that a little. You can still see a little of that in the code - the reasons why there are no intersections are still in the comments
/// <summary>
/// Calculates intersection - if any - of two lines
/// </summary>
/// <param name="otherLine"></param>
/// <returns>Intersection or null</returns>
/// <remarks>Taken from http://tog.acm.org/resources/GraphicsGems/gemsii/xlines.c </remarks>
public Point? Intersection(LineF otherLine)
{
  var a1 = Y2 - Y1;
  var b1 = X1 - X2;
  var c1 = X2 * Y1 - X1 * Y2;

  /* Compute r3 and r4.
   */

  var r3 = a1 * otherLine.X1 + b1 * otherLine.Y1 + c1;
  var r4 = a1 * otherLine.X2 + b1 * otherLine.Y2 + c1;

  /* Check signs of r3 and r4.  If both point 3 and point 4 lie on
   * same side of line 1, the line segments do not intersect.
   */

  if (r3 != 0 && r4 != 0 && Math.Sign(r3) == Math.Sign(r4))
  {
    return null; // DONT_INTERSECT
  }

  /* Compute a2, b2, c2 */

  var a2 = otherLine.Y2 - otherLine.Y1;
  var b2 = otherLine.X1 - otherLine.X2;
  var c2 = otherLine.X2 * otherLine.Y1 - otherLine.X1 * otherLine.Y2;

  /* Compute r1 and r2 */

  var r1 = a2 * X1 + b2 * Y1 + c2;
  var r2 = a2 * X2 + b2 * Y2 + c2;

  /* Check signs of r1 and r2.  If both point 1 and point 2 lie
   * on same side of second line segment, the line segments do
   * not intersect.
   */
  if (r1 != 0 && r2 != 0 && Math.Sign(r1) == Math.Sign(r2))
  {
    return (null); // DONT_INTERSECT
  }

  /* Line segments intersect: compute intersection point. 
   */

  var denom = a1 * b2 - a2 * b1;
  if (denom == 0)
  {
    return null; //( COLLINEAR );
  }
  var offset = denom < 0 ? -denom / 2 : denom / 2;

  /* The denom/2 is to get rounding instead of truncating.  It
   * is added or subtracted to the numerator, depending upon the
   * sign of the numerator.
   */

  var num = b1 * c2 - b2 * c1;
  var x = (num < 0 ? num - offset : num + offset) / denom;

  num = a2 * c1 - a1 * c2;
  var y = (num < 0 ? num - offset : num + offset) / denom;
  return new Point(x, y);
}

Now because I needed to be able to find intersections with rectangles as well, I made some extension methods that work on the RectangleF class that is in my wp7nl library on codeplex.

namespace Wp7nl.Utilities
{
  public static class LineFExtensions
  {
    public static List<Point> Intersection(this LineF line, RectangleF rectangle)
    {
      var result = new List<Point>();
      AddIfIntersect(line, rectangle.X, rectangle.Y, rectangle.X2, rectangle.Y, 
                     result);
      AddIfIntersect(line, rectangle.X2, rectangle.Y, rectangle.X2, rectangle.Y2, 
                     result);
      AddIfIntersect(line, rectangle.X2, rectangle.Y2, rectangle.X, rectangle.Y2, 
                     result);
      AddIfIntersect(line, rectangle.X, rectangle.Y2, rectangle.X, rectangle.Y, 
                     result);
      return result;
    }

    private static void AddIfIntersect(LineF line, 
                                       double x1, double y1, double x2, 
                                       double y2, ICollection<Point> result)
    {
      var l2 = new LineF(x1, y1, x2, y2);
      var intersection = line.Intersection(l2);
      if (intersection != null)
      {
        result.Add(intersection.Value);
      }
    }

    /// <summary>
    /// If dx =1 , dy = ??
    /// </summary>
    /// <param name="line"></param>
    /// <returns></returns>
    public static double GetDy(this LineF line)
    {
       var dx = Math.Abs(line.X1 - line.X2);
      var dy = line.Y1 - line.Y2;
      return (dy / dx);
    }
  }
}

This I actually wrote myself, and what is simply does is break the rectangle into four lines and tries to find intersections with each of those lines. The result is a list of Point which is either empty or contains points.

And to prove it actually works, I wrote this little sample Windows Phone application that generates 15 random lines and tries to find the intersection points between all the 15 lines and one fixed rectangle. This gives a this kind of minimalistic art-like results:

intersections1intersections2intersections3

Visual proof is maybe not the best, but most certainly the most fun. So this is what I use to determine where the ball in 2 Phone Pong needs to bounce – namely when its trajectory intersects with either the screen side or the paddle.

I hope this is useful to anyone. Write a game with it and ping me back ;-)

24 September 2013

A behavior to implement a scroll-into-view panel (for a Facebook-like GUI) on Windows Phone

As promised, this post describes a behavior to scroll parts of a Windows Phone GUI into view, after I first described how you can create such panels by making creative use of scaling. This can also bee seen as part 4 of my animation-trilogy as it is based heavily on the groundwork laid there. Which goes to show creativity cannot me planned;-)

This behavior is also a very versatile, in the sense that can be used to move any GUI element from any location to another, but I use it now to make a scroll-into-view panel.

Setup

imageI started out with the final sample of my previous post. Then I changed a few minor things:

  • I selected the MessagePanel1 and changed the Colum to 0 and the Columnspan to 2.
  • I selected the Grid below MessagePanel and gave it a blue solid color background brush
  • Set the width to 228 (it is now set to 228 (Auto), fill in a hard coded value).
  • I selected the Textblock below the grid and changed the text “This is Panel 2” to “Settings”

Net result is displayed to the right.

First, a little refactoring

imageIn the first part of my animation behavior series  I created a base class called BaseScaleBehavior. Turned out that was a great base for not only scaling animations, but also other kinds of animations – provided I got rid of a few things. So I created a new base class BaseAnimationBehavior – with basically all the data from BaseScaleBehavior, excluding the Direction, and made BaseScaleBehavior descend from that. Visual Studio (that is, if you have right version) generates this nice diagram for it:

On top we see the new BaseAnimationbehavior, with it’s child class BaseScaleBehavior. This now inherits all properties from BaseAnimationbehavior so as far as the existing behaviors are concerned, nothing has changed. But on the right side there is now room for the new MoveObjectbehavior

The behavior itself

BaseAnimationbehavior has only two properties left that you can set – Duration (the time the effect should take) and “Activate” –  a boolean that indicates if the effect should be visible (true) or not. Any descending behavior should implement BuildTransform (to create the Transform for the current state) and BuildStoryBoard (to create a StoryBoard for a transition).

The MirrorBehavior introduces two extra properties that you can set: ActivatedXValue and ActivatedYValue. They are both of type “double?” – that is, nullable double. After all, they need not to be set – if you, like me, want to move only in one direction (horizontal, that is) The behavior assumes at startup that wherever the object it attached to is on the screen now, that’s if default location (for Activated = false). So you need only to supply the new values – and it must me relative values. If you want the screen to move to the left, you should provide a negative value. –228, to be precise – exactly the width of the Settings panel.

The behavior starts rather simple, as it is rather simple – most of the heavy lifting is done by already published code.

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using Wp7nl.Utilities;

namespace Wp7nl.Behaviors
{
  public class MoveObjectBehavior : BaseAnimationBehavior
  {
    protected override void OnSetup()
    {
      originalTranslation = GetInitialTranslation();
      base.OnSetup();
    }

    private Point originalTranslation;

    private Point GetInitialTranslation()
    {
      return AssociatedObject.GetCompositeTransform() != null ? 
        AssociatedObject.GetTranslatePoint() : new Point(0, 0);
    }
  }
}

The behavior starts by checking if there’s a transformation defined and tries to get the translation point from that – in other words, is this object already moved from its place using a translation? If not, then assume a translation of 0.

The BuildTransform of this behavior is pretty simple:

protected override CompositeTransform BuildTransform()
{
  return new CompositeTransform
  {
    TranslateX = Activated && ActivatedXValue != null ? 
      ActivatedXValue.Value : originalTranslation.X,
    TranslateY = Activated && ActivatedYValue != null ? 
      ActivatedYValue.Value : originalTranslation.Y
  };
}

It sets the X translation to the ActivatedX value if Activated is true and if there is and ActivatedX value defined (it was nullable, remember, so it’s entirely possible it is not – and in all other cases it just uses the original translation value. Repeat for Y.

And the final part of this behavior is a matter of building the Storyboard using the age old AddTranslationAnimation and GetTranslatePoint extension methods that I already wrote back in March 2011

protected override Storyboard BuildStoryBoard()
{
  var storyboard = new Storyboard { FillBehavior = FillBehavior.HoldEnd };
  var transform = BuildTransform();
  var duration = new Duration(TimeSpan.FromMilliseconds(Duration));
  storyboard.AddTranslationAnimation(
    AssociatedObject,
    AssociatedObject.GetTranslatePoint(), 
new Point(transform.TranslateX, transform.TranslateY), duration); return storyboard; }

The effect

The effect, if I may say so myself in all modesty, is rather charming. And, by the way, in this little sample solution it’s also ViewModel Driven.

MoveObjectBehavior in action
I used this ├╝bersimple viewmodel
using System.Windows.Input;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;

namespace XamlScale
{
  public class DemoViewModel : ViewModelBase
  {
    private bool showSettings;
    public bool ShowSettings
    {
      get { return showSettings; }
      set
      {
        if (showSettings != value)
        {
          showSettings = value;
          RaisePropertyChanged(() => ShowSettings);
        }
      }
    }
    public ICommand MyCommand
    {
      get
      {
        return new RelayCommand(
            () =>
            {
              ShowSettings = !ShowSettings;
            });
      }
    }
  }
}

imageTo drive this behavior: simply bind the viewmodels’ MyCommand command to the button with Blend, and the ShowSettings property to the Activated property of the behavior. And then fill in –228 for “ActivatedX”

And that’s all there is to it. The demo solution contains all code displayed in this sample, including the revised behaviors of my earlier series – but they are not really used in the sample.

For the record – I wrote this behavior as part of the 1.1 update of 2 Phone Pong during my holiday, my Surface Pro sitting on the garden table next to our vacation house in Schluchsee in the Schwarzwald (Black Forest), Baden-Wuttenberg, Germany, my wife on next to me reading a book, after a long mountain walk on a beautiful sunny day. While it got slowly dark, we rested from our day’s journey, tea was being consumed, and the typical non-committal carefree talk of a summer holiday evening was going on, this thingy was created.  Fond memories. *sigh*.

18 September 2013

Aligning XAML elements outside the screen using scaling (for a Facebook-like GUI)

This is a trick I use to make partial screens outside of the actual Windows Phone viewport, for instance like the Facebook app for Windows Phone does – that has these ‘side panels’ that slide into view when you tap the “settings” button. Some people like it, some people hate it for being to iOS-y or to Android-y – I just show you how I do it.

This a two part blog post. This first one will show you how the XAML trick is being used an why it works – the second one will cover a behavior for animating the screen.

I start with a standard Windows Phone app and add the following XAML inside the ContentPanel

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="0.5*"/>
    <ColumnDefinition Width="0.5*"/>
  </Grid.ColumnDefinitions>
  <Grid Column="1" x:Name="MessagePanel1">
    <TextBlock Text="This is panel1" FontSize="29.333"></TextBlock>
  </Grid>
  <Grid Column="1" x:Name="MessagePanel2" RenderTransformOrigin="0.5,0.5">
    <TextBlock Text="This is panel2" FontSize="29.333" FontFamily="Andalus"/>
  </Grid>
</Grid>

imageSo basically I define a grid that divides my screen vertically in two parts, but both panels are in the same (second column). Now save everything, and open the app in Blend. You will see the following extreme ugly screen as displayed to the right.

As you can see the two panels are on top of each other. I changed the font of the second panel to illustrate that. Now move over to the Objects and Timeline panel and expand till it looks like this:

image

imageNo follow the following procedure:

  • Right-click on TextBox,
  • Click Group Into
  • Select “Grid”

 

 

imageSo now we have a grid around the textbox. Select that grid, then go as follows

  • With the grid selected, go to the right hand side of the screen and find the “Transform” panel. Expand it if necessary. Selected the “Flip” tab, flip the screen horizontally by clicking the “Flip X-axis” button

 

image

  • Now go one level up, and select the MessagePanel 2.
  • Click the “Flip X-axis” button again.
  • And now for the coupe de grace: select Grid again
  • Select the Center Point tab
  • Set X to 1

 

imageCongratulations. You have probably now found the most complex way to align to two panels together one screen. Why not simply put the Panel2 in a grid column 0? Well… Go back to the transform panel and change the “1” behind X to “-1:

image

Now you have a screen just outside the screen. Well, almost. Because of the offset of the content panel is 12, you can just about see the leftmost part of panel 2. This is easily fixed (see below)

 

 

 

 

 

image

  • Select MessagePanel 2 again.
  • Go to the Translate Panel again
  • Open the “Translate” tab”
  • Fill in “12” for Translate X

And done.

imageNow if you simply select ContentPanel, click on the Translate X field again and roll down your mouse wheel you will see the the number go below zero and whole screen move to the left, until the whole op panel 2 comes into view (this happens at about –235). Now the only thing we need to do is create an animation that will perform the scrolling. You can do that either in Blend with the Visual State Manager, or with a behavior. I, naturally, choose the latter part. I use both this trick in 2 Phone Pong  - not for a settings screen, but to scroll in an advertisement for a more or less secret in-app purchase when the game comes in a certain state (hint – especially when you loose a lot). 

By using this double mirroring (actually scaling to “-1”, as a look in the XAML will tell you) and center point trick, things will always outline automatically.

So this was part 1. The demo solution, showing the situation above (and not to the right) shows the situation before the screen is translated to the left. Next time I will show you a behavior that can actually be used to simply automate the animation.

Finally, this trick will work on any XAML platform, not just on Windows Phone. Once again, Blend is your friend. Remember that.

15 September 2013

Zero lines of code solution for in-app checking for updates on Windows Phone

“Good artists copy; great artists steal” –Steve Jobs

Every Windows Phone developer who has non-tech friends, relatives or a wife with a Windows Phone knows the problem: a lot of users don’t check their Store regularly and simply don’t update their apps – or at least not often enough. The highly intelligent Pedro Lamas – Senior Nokia engineer, author of the Cimbalino Windows Phone toolkit, and my personal savior when I ran into some very exotic problems with Nokia Music – recently described a way to automatically check for updates inside the app.With his permission, I decided to pack the core logic into a behavior, much like I did with the ratings logic in my previous post – so you can essentially drag this on your main app page and be done with it.Pedro has used something like my SafeBehavior in Cimbalino, and now I use some of his code in the wp7nl library on codeplex. This is how community works. In that light the quote on top of this article is rather badly chosen ;-)

If you drop the UpgradeCheckBehavior, as I have christened this thing, onto the main page of your application, Blend will present you with only two options: a message box caption and a message box text:

image

  • Caption is the text that will appear on the message box when the behavior detects a new version. Default value is “New version!”
  • Message is the text that will appear inside the message box when the behavior detects a new version. Default value is “There's a new version of this app available, do you want to update?”

If you are fine with that, you are finished. The app will check for updates automatically on app startup.

The behavior itself is a rather simple SafeBehavior and goes like this:

using System;
using System.Globalization;
using System.Net;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Xml;
using Microsoft.Phone.Tasks;
using Wp7nl.Utilities;

namespace Wp7nl.Behaviors
{
  /// <summary>
  /// A behavior checking from in the app if there's an update available. 
  /// </summary>
  public class UpgradeCheckBehavior : SafeBehavior<Page>
  {
    private ManifestAppInfo appInfo;

    protected override void OnSetup()
    {
      appInfo = new ManifestAppInfo();
      CheckUpgrade();
    }

    private void CheckUpgrade()
    {
#if !DEBUG
      GetLatestVersion().ContinueWith(ProcessResult);
#endif
    }
  }
}

Since in debug mode the app will run on you phone or emulator using a generated temporary app id, it won’t be possible to check for new versions anyway so I’ve added an #if statement around the actual check.

Using my ManifestAppInfo helper class I retrieve all the app’s metadata which is used by the GetLatestVersion – in essence a slightly modified version of Pedro’s work:

/// <summary>
/// This method is almost 100% stolen from 
/// http://www.pedrolamas.com/2013/07/24/checking-for-updates-from-inside-a-windows-phone-app/
/// </summary>
private Task<Version> GetLatestVersion()
{
  var cultureInfoName = CultureInfo.CurrentUICulture.Name;
  var url = string.Format(
      "http://marketplaceedgeservice.windowsphone.com/v8/catalog/apps/{0}?os={1}&cc={2}&oc=&lang={3}​",
      appInfo.ProductId,
      Environment.OSVersion.Version,
      cultureInfoName.Substring(cultureInfoName.Length - 2).ToUpperInvariant(),
      cultureInfoName);

  var request = WebRequest.Create(url);

  return Task.Factory.FromAsync(request.BeginGetResponse, result =>
  {
    try
    {
      var response = (HttpWebResponse)request.EndGetResponse(result);
      if (response.StatusCode != HttpStatusCode.OK)
      {
        throw new WebException("Http Error: " + response.StatusCode);
      }

      using (var outputStream = response.GetResponseStream())
      {
        using (var reader = XmlReader.Create(outputStream))
        {
          reader.MoveToContent();
          var aNamespace = reader.LookupNamespace("a");
          reader.ReadToFollowing("entry", aNamespace);
          reader.ReadToDescendant("version");
          return new Version(reader.ReadElementContentAsString());
        }
      }
    }
    catch (Exception)
    {
      return null;
    }
  },
  null);
}

I think my only addition to this is the try-catch around the method as I tended to have some odd errors sometimes when running it inside Visual Studio. This method craftily downloads the app metadata from the store and extracts a version from it.

And then the only things left of course are comparing the retrieved version to the current version, and if the current version is greater, displaying a message box asking the user to upgrade:

private void ProcessResult(Task<Version> t)
{
  if(t.IsCompleted && t.Result != null )
  {
    var currentVersion = new Version(appInfo.Version);
    if (currentVersion < t.Result )
    {
      DoShowUpgrade();
    }
  }
}

private void DoShowUpgrade()
{
  Deployment.Current.Dispatcher.BeginInvoke(() =>
  {
    var result = MessageBox.Show(Message, Caption, MessageBoxButton.OKCancel);
    if (result == MessageBoxResult.OK)
    {
      var marketplaceReviewTask = new MarketplaceDetailTask();
      try
      {
        marketplaceReviewTask.Show();
      }
      catch (InvalidOperationException ex)
      {
      }
    }
  });
}
newversionAnd that's all there's to it. The two dependency properties holding caption and message have been omitted for the sake of brevity. The sad thing of Pedro’s brilliant idea is that it’s quite hard to check if it actually works. Well let me assure you it does, and if you run the demo solution in release mode configuration, it will show you by actually asking for an upgrade:

How is that possible? The app created by Visual Studio runs a temporary ID that should not even be in the Store! That’s correct, unless you make it have a real id. So I opened the WPAppManifest.xml file that’s over in the Properties folder and messed a little with the settings:image

I changed the app Id to that of my latest game 2 Phone Pong in the store, and changed the version number to 0.9.0.0 (while the version number in the Store of course is at least 1.0.0.0). Now the app thinks ask the store for the version number of 2 Phone Pong, gets (at the time of this writing) 1.0.0.0 back, ascertains that’s lower than it’s current version and pops up the message. I you hit the OK button it will actually take you to 2 Phone Pong in the Store . This proves Pedro’s code actually works, and you have now a zero code solution to take your users to the best possible version of your app – and no longer an excuses not to do it;-)

Warning – don’t try to deploy a debug version of your app with this id trick on a phone that has the actual app downloaded from the Store on it. That won’t work – you won’t have writing permissions. I haven’t tried the opposite – downloading an app from the store over an app deployed from Visual Studio – but I can imagine that way only lie mud pies.

I will include this soon in the upcoming version of my wp7nl library on codeplex

12 September 2013

Zero lines of code solution to entice Windows Phone users to rate and review an app

I don’t think I need to elaborate on how important it is to get ratings for your app in the Store – and preferably good ratings. By no means this is new and original: Matthijs Hoekstra wrote something to this effect, our Dutch DPE Rajen Kishna even made a NuGet package for similar stuff, Telerik have something in their magnificent Radcontrols for Windows Phone  and yet me, being stubborn, need to make something of my own. The reason for this is simple: I wanted (of course) to make a behavior so you can add it to your app without any code at all – just drag it on top of your first opening page and it will work out of the box. And Blend will present you with some properties that you can set – or not. It works fine out of the box. As it does in my latest Windows Phone app, 2 Phone Pong.

If you drop the behavior on top of your start page it will work without modification. But Blend exposes four properties to customize it’s mode of operation:

image

  • Caption is the text on top of the message box that will display when the app reminds the user. Default is “Review App”. You can set a different value in XAML or (better) bind it to a view model property holding a globalized text.
  • MaxReminders is the number of times the behavior will ask the user to review. If the user refuses to review more than MaxReminders time, he will no longer be bothered.
  • Message shows the actual reminder message. Default values is “You have used this app a few times now, would you like to review it in the store?”
  • RemindFrequency is the number of app startups after which the review request is displayed.

So, with the default setting, the app will ask you the 7th, 14th and 21st time if you want to review the app. After the third dismiss, it won’t ask you anymore. This is to prevent users getting annoyed by endless review requests and giving negative reviews because of that. And of course it will stop asking the user when has elected to post a review.

The behavior itself is built on top of my wp7nl library on codeplex (of course) and implemented as a SafeBehavior. First, I created a simple data class to hold the data in local storage:

namespace Wp7nl.Behaviors
{
  /// <summary>
  /// Simple data class to store data in used by RemindReviewBehavior
  /// </summary>
  public class RemindData
  {
    public int Starts { get; set; }

    public bool Reviewed { get; set; }

    public bool Refused { get; set; }
  }
}

The behavior itself is also pretty simple – it sports four Dependency Properties with the same names as Blend shows – not coincidentally – in front of the text boxes in the image on top of this post.

The behavior itself starts simple enough, being a standard SafeBehavior:

namespace Wp7nl.Behaviors
{
  /// <summary>
  /// A behavior to remind the user to review the app after a couple
  /// times using it
  /// </summary>
  public class RemindReviewBehavior: SafeBehavior<Page>
  {
    protected override void OnSetup()
    {
      CheckRemind();
   }
}

All the functionality is in the CheckRemind method:

private void CheckRemind()
{
  var helper = new IsolatedStorageHelper<RemindData>();
  var remindData = 
helper.ExistsInStorage() ? helper.RetrieveFromStorage() : new RemindData(); if (!remindData.Reviewed && !remindData.Refused) { remindData.Starts++; if (remindData.Starts % RemindFrequency == 0) { var result = MessageBox.Show(Message, Caption, MessageBoxButton.OKCancel); if (result == MessageBoxResult.OK) { Review(); remindData.Reviewed = true; } else { if (remindData.Starts >= MaxReminders * RemindFrequency) { remindData.Refused = true; } } } helper.SaveToStorage(remindData); } }

Using the IsolatedStorageHelper from wp7nl it checks if there is already data from a previous run in local storage – if there is not, it is created. If Reviewed or Refused are true, no action in necessary. After, the number or starts is increased, and it checks if the number of starts can be divided by the RemindFrequency. If that is the case, the message is displayed,

If the user then decides to review the app, the Review method called and the Reviewed property is set to true so the user won’t be bothered anymore. If the user does not want to review, the app checks if the max number of review request has already been put out – and if so, the Refused property is set to true. The user is (also) no longer bothered anymore. And at the end, the remindData is saved so whatever happened in the method is saved for posterity.

The Review method then is pretty simple:

private void Review()
{
  var marketplaceReviewTask = new MarketplaceReviewTask();
  try
  {
    marketplaceReviewTask.Show();
  }
  catch (InvalidOperationException ex)
  {
  }
}

ReviewAppThe only drawback is that the user can click OK, go to the Store, and then hit cancel. There is no way around cheaters, but if someone does not want to review, whatever – at least he/she then won’t give a bad review either.

The four dependency properties I leave out for the sake of brevity.

I have put the code into upcoming version of the wp7nl library, but for now you can get it from the demo solution. I have changed MaxReminders to 20 and RemindFrequency to 2 so the demo app will ask you every other time to rate it, for 20 times. This is a setting I would definitely not recommend in the wild, but it shows the point.

Now Matthijs, Rajen, me and several others have showed you multiple ways to get this done. Mine does not even require you to code – just drag and drop. Now make sure you implement any of these solutions. Whether you are in the Windows Phone game for fun, glory, money or all of the above – you want those apps downloaded. And ratings are crucial for that.