November 2011

Volume 26 Number 11

Windows Phone SDK 7.1 - Building a 'Mango' App

By Andrew Whitechapel | November 2011

“Mango” is the internal code name for the Windows Phone SDK 7.1 release, and of course the name of a delicious tropical fruit. There are many ways you can use mangoes—for example, in pies, salads and a range of cocktails. The mango is also said to provide a number of health benefits, and it has an interesting cultural history. In this article, I’ll examine Mangolicious, a Windows Phone SDK 7.1 application about mangoes. The application provides a range of mango recipes, cocktails and facts, but the real purpose is to explore some of the big new features in the 7.1 release, specifically:

  • Local database and LINQ to SQL
  • Secondary tiles and deep linking
  • Silverlight/XNA integration

The application’s user experience is simple: The main page offers a panorama, with a menu on the first panorama item, a dynamic selection of the current season’s recipes and cocktails on the second item, and some simple “about” information on the third item, as shown in Figure 1.

Mangolicious Panorama Main Page
Figure 1 Mangolicious Panorama Main Page

Both the menu and the items in the Seasonal Highlights section act as links to navigate to the other pages in the application. The majority of the pages are straightforward Silverlight pages, and one page is dedicated to an integrated XNA game. Here’s a summary of the tasks required to build this application, from start to finish:

  1. Create the basic solution in Visual Studio.
  2. Independently create the database for the recipe, cocktail and fact data.
  3. Update the application to consume the database and expose it for data binding.
  4. Create the various UI pages and data bind them.
  5. Set up the Secondary Tiles feature to allow the user to pin Recipe items to the phone’s Start page.
  6. Incorporate an XNA game into the application.

Create the Solution

For this application, I’ll use the Windows Phone Silverlight and XNA Application template in Visual Studio. This generates a solution with three projects; after renaming, these are summarized in Figure 2.

Figure 2 Projects in a Windows Phone Silverlight and XNA Solution

Project Description
MangoApp Contains the phone application itself, with a default MainPage and a secondary GamePage.
GameLibrary An essentially empty project that has all the right references, but no code. Crucially, it includes a Content Reference to the Content project.
GameContent An empty Content project, which will hold all the game assets (images, sound files and so on).

Create the Database and DataContext Class

The Windows Phone SDK 7.1 release introduces support for local databases. That is, an application can store data in a local database file (SDF) on the phone. The recommended approach is to create the database in code, either as part of the application itself or via a separate helper application that you build purely to create the database. It makes sense to create the database within your application in scenarios where you’ll be creating most or all of the data only when the application runs. For the Mangolicious application, I have only static data, and I can populate the database in advance.

To do this, I’ll create a separate database-creator helper application, starting with the simple Windows Phone Application template. To create the database in code, I need a class derived from DataContext, which is defined in the custom Phone version of the System.Data.Linq assembly. This same DataContext class can be used both in the helper application that creates the database and the main application that consumes the database. In the helper application, I must specify the database location to be in isolated storage, because that’s the only location I can write to from a phone application. The class also contains a set of Table fields for each database table:

public class MangoDataContext : DataContext
{
  public MangoDataContext()
    : base("Data Source=isostore:/Mangolicious.sdf") { }
 
  public Table<Recipe> Recipes;
  public Table<Fact> Facts;
  public Table<Cocktail> Cocktails;
}

There’s a 1:1 mapping between Table classes in the code and tables in the database. The Column properties map to the columns in the table in the database, and include the database schema properties such as the data type and size (INT, NVARCHAR and so on), whether the column may be null, whether it’s a key column and so on. I define Table classes for all the other tables in the database in the same way, as shown in Figure 3.

Figure 3 Defining Table Classes

[Table]
public class Recipe
{
  private int id;
  [Column(
    IsPrimaryKey = true, IsDbGenerated = true,
    DbType = "INT NOT NULL Identity", CanBeNull = false,
    AutoSync = AutoSync.OnInsert)]
  public int ID
  {
    get { return id; }
    set
    {
      if (id != value)
      {
        id = value;
      }
    }
  }
 
  private string name;
  [Column(DbType = "NVARCHAR(32)")]
  public string Name
  {
    get { return name; }
    set
    {
      if (name != value)
      {
        name = value;
      }
    }
  }?
    ... additional column definitions omitted for brevity
}

Still, in the helper application—and using a standard Model-View-ViewModel (MVVM) approach—I now need a ViewModel class to mediate between the View (the UI) and the Model (the data) using the DataContext class. The ViewModel has a DataContext field and a set of collections for the table data (Recipes, Facts and Cocktails). The data is static, so simple List<T> collections are sufficient here. For the same reason, I only need get property accessors, not setmodifiers (see Figure 4).

Figure 4 Defining Collection Properties for Table Data in the ViewModel

public class MainViewModel
{
  private MangoDataContext mangoDb;
 
  private List<Recipe> recipes;
  public List<Recipe> Recipes
  {
    get
    {
      if (recipes == null)
      {
        recipes = new List<Recipe>();
      }
    return recipes;
    }
  }
 
    ... additional table collections omitted for brevity
}

I also expose a public method—which I can invoke from the UI—to actually create the database and all the data. In this method, I create the database itself if it doesn’t already exist and then create each table in turn, populating each one with static data. For example, to create the Recipe table, I create multiple instances of the Recipe class, corresponding to rows in the table; add all the rows in the collection to the DataContext; and finally commit the data to the database. The same pattern is used for the Facts and Cocktails tables (see Figure 5).

Figure 5 Creating the Database

public void CreateDatabase()
{
  mangoDb = new MangoDataContext();
  if (!mangoDb.DatabaseExists())
  {
    mangoDb.CreateDatabase();
    CreateRecipes();
    CreateFacts();
    CreateCocktails();
  }
}
 
private void CreateRecipes()
{
  Recipes.Add(new Recipe
  {
    ID = 1,
    Name = "key mango pie",
    Photo = "Images/Recipes/MangoPie.jpg",
    Ingredients = "2 cans sweetened condensed milk, ¾ cup fresh key lime juice, ¼ cup mango purée, 2 eggs, ¾ cup chopped mango.",
    Instructions = "Mix graham cracker crumbs, sugar and butter until well distributed. Press into a 9-inch pie pan. Bake for 20 minutes. Make filling by whisking condensed milk, lime juice, mango purée and egg together until blended well. Stir in fresh mango. Pour filling into cooled crust and bake for 15 minutes.",
    Season = "summer"
  });
 
    ... additional Recipe instances omitted for brevity
 
  mangoDb.Recipes.InsertAllOnSubmit<Recipe>(Recipes);
  mangoDb.SubmitChanges();
}

At a suitable point in the helper application—perhaps in a button click handler—I can then invoke this CreateDatabase method. When I run the helper (either in the emulator or on a physical device), the database file will be created in the application’s isolated storage. The final task is to extract that file to the desktop so I can use it in the main application. To do this, I’ll use the Isolated Storage Explorer tool, a command-line tool that ships with the Windows Phone SDK 7.1. Here’s the command to take a snapshot of isolated storage from the emulator to the desktop:

"C:\Program Files\Microsoft SDKs\Windows Phone\v7.1\Tools\IsolatedStorageExplorerTool\ISETool" ts xd {e0e7e3d7-c24b-498e-b88d-d7c2d4077a3b} C:\Temp\IsoDump

This command assumes the tool is installed in a standard location. The parameters are explained in Figure 6.

Figure 6 Isolated Storage Explorer Command-Line Parameters

Parameter Description
ts “Take snapshot” (the command to download from isolated storage to the desktop).
xd Short for XDE (that is, the emulator).
{e0e7e3d7-c24b-498e-b88d-d7c2d4077a3b} The ProductID for the helper application. This is listed in the WMAppManifest.xml and is different for each application.
C:\Temp\IsoDump Any valid path on the desktop where you want to copy the snapshot to.

Having extracted the SDF file to the desktop, I’m now finished with the helper application and can turn my attention to the Mangolicious application that will consume this database.

Consume the Database

In the Mangolicious application, I add the SDF file to the project and also add the same custom DataContext class to the solution, with a couple of minor changes. In Mangolicious, I don’t need to write to the database, so I can use it directly from the application install folder. Thus the connection string is slightly different from the one in the helper application. Also, Mangolicious defines a SeasonalHighlights table in code. There’s no corresponding SeasonalHighlight table in the database. Instead, this code table pulls data from two underlying database tables (Recipes and Cocktails) and is used to populate the Seasonal Highlights panorama item. These two changes are the only differences in the DataContext class between the database-creation helper application and the Mangolicious database-consuming application:

public class MangoDataContext : DataContext
{
  public MangoDataContext()
    : base("Data Source=appdata:/Mangolicious.sdf;File Mode=read only;") { }
 
  public Table<Recipe> Recipes;
  public Table<Fact> Facts;
  public Table<Cocktail> Cocktails;
  public Table<SeasonalHighlight> SeasonalHighlights;
}

The Mangolicious application also needs a ViewModel class, and I can use the ViewModel class from the helper application as a starting point. I need the DataContext field and the set of List<T> collection properties for the data tables. On top of that, I’ll add a string property to record the current season, computed in the constructor:

public MainViewModel()
{
  season = String.Empty;
  int currentMonth = DateTime.Now.Month;
  if (currentMonth >= 3 && currentMonth <= 5) season = "spring";
  else if (currentMonth >= 6 && currentMonth <= 8) season = "summer";
  else if (currentMonth >= 9 && currentMonth <= 11) season = "autumn";
  else if (currentMonth == 12 || currentMonth == 1 || currentMonth == 2)
    season = "winter";
}

The critical method in the ViewModel is the LoadData method. Here, I initialize the database and perform LINQ-to-SQL queries to load the data via the DataContext into my in-memory collections. I could preload all three tables at this point, but I want to optimize startup performance by delaying the loading of data unless and until the relevant page is actually visited. The only data I must load at startup is the data for the SeasonalHighlight table, because this is displayed on the main page. For this, I have two queries to select only rows from the Recipes and Cocktails tables that match the current season, and add the combined row sets to the collection, as shown in Figure 7.

Figure 7 Loading Data at Startup

public void LoadData()
{
  mangoDb = new MangoDataContext();
  if (!mangoDb.DatabaseExists())
  {
    mangoDb.CreateDatabase();
  }
 
  var seasonalRecipes = from r in mangoDb.Recipes
                        where r.Season == season
                        select new { r.ID, r.Name, r.Photo };
  var seasonalCocktails = from c in mangoDb.Cocktails
                          where c.Season == season
                          select new { c.ID, c.Name, c.Photo };
 
  seasonalHighlights = new List<SeasonalHighlight>();
  foreach (var v in seasonalRecipes)
  {
    seasonalHighlights.Add(new SeasonalHighlight {
      ID = v.ID, Name = v.Name, Photo = v.Photo, SourceTable="Recipes" });
  }
  foreach (var v in seasonalCocktails)
  {
    seasonalHighlights.Add(new SeasonalHighlight {
      ID = v.ID, Name = v.Name, Photo = v.Photo, SourceTable = "Cocktails" });
  }
 
  isDataLoaded = true;
}

I can use similar LINQ-to-SQL queries to build separate LoadFacts, LoadRecipes and LoadCocktails methods that can be used after startup to load their respective data on demand.

Create the UI

The main page consists of a Panorama with three PanoramaItems. The first item consists of a ListBox that offers a main menu for the application. When the user selects one of the ListBox items, I navigate to the corresponding page—that is, the collection page for either Recipes, Facts and Cocktails—or the Game page. Just before navigating, I make sure to load the corresponding data into the Recipes, Facts or Cocktails collections:

switch (CategoryList.SelectedIndex)
{
  case 0:
    App.ViewModel.LoadRecipes();
    NavigationService.Navigate(
      new Uri("/RecipesPage.xaml", UriKind.Relative));
    break;
 
... additional cases omitted for brevity
}

When the user selects an item from the Seasonal Highlights list in the UI, I examine the selected item to see whether it’s a Recipe or a Cocktail, and then navigate to the individual Recipe or Cocktail page, passing in the item ID as part of the navigation query string, as shown in Figure 8.

Figure 8 Selecting from the Seasonal Highlights List

SeasonalHighlight selectedItem =
  (SeasonalHighlight)SeasonalList.SelectedItem;
String navigationString = String.Empty;
if (selectedItem.SourceTable == "Recipes")
{
  App.ViewModel.LoadRecipes();
  navigationString =
    String.Format("/RecipePage.xaml?ID={0}", selectedItem.ID);
}
else if (selectedItem.SourceTable == "Cocktails")
{
  App.ViewModel.LoadCocktails();
  navigationString =
    String.Format("/CocktailPage.xaml?ID={0}", selectedItem.ID);
}
NavigationService.Navigate(
  new System.Uri(navigationString, UriKind.Relative));

The user can navigate from the menu on the main page to one of three listing pages. Each of these pages data binds to one of the collections in the ViewModel to display a list of items: Recipes, Facts or Cocktails. Each of these pages offers a simple ListBox where each item in the list contains an Image control for the photo and a TextBlock for the name of the item. For example, Figure 9 shows the FactsPage.

Fun Facts, One of the Collection List Pages
Figure 9 Fun Facts, One of the Collection List Pages

When the user selects an individual item from the Recipes, Facts or Cocktails lists, I navigate to the individual Recipe, Fact or Cocktail page, passing down the ID of the individual item in the navigation query string. Again, these pages are almost identical across the three types, each one offering an Image and some text below. Note that I don’t define an explicit style for the databound TextBlocks, but that they all nonetheless use TextWrapping=Wrap. This is done by declaring a TextBlock style in the App.xaml.cs:

<Style TargetType="TextBlock" BasedOn="{StaticResource
  PhoneTextNormalStyle}">
  <Setter Property="TextWrapping" Value="Wrap"/>
</Style>

The effect of this is that any TextBlock in the solution that doesn’t explicitly define its own style will implicitly use this one instead. Implicit styling is another new feature introduced in the Windows Phone SDK 7.1 as part of Silverlight 4.

The codebehind for each of these pages is simple. In the OnNavigatedTo override, I extract the individual item ID from the query string, find that item from the ViewModel collection and data bind to it. The code for the RecipePage is a little more complex than the others—the additional code in this page is all related to the HyperlinkButton positioned at the top-right-hand corner of the page. This can be seen in Figure 10.

A Recipe Page with Pin Button
Figure 10 A Recipe Page with Pin Button

Secondary Tiles

When the user clicks the “pin” HyperlinkButton on the individual Recipe page, I pin that item as a tile on the phone’s Start page. The act of pinning takes the user to the Start page and deactivates the application. When a tile is pinned in this way, it animates periodically, flipping between front and back, as shown in Figure 11 and Figure 12.

Pinned Recipe Tile (Front)
Figure 11 Pinned Recipe Tile (Front)

Pinned Recipe Tile (Back)
Figure 12 Pinned Recipe Tile (Back)

Subsequently, the user may tap this pinned tile, which navigates directly to that item within the application. When he reaches the page, the “pin” button will now have an “unpin” image. If he unpins the page, it will be removed from the Start page, and the application continues.

Here’s how this works. In the OnNavigatedTo override for the RecipePage, after doing the standard work to determine which specific Recipe to data bind to, I formulate a string that I can use later as the URI for this page:

thisPageUri = String.Format("/RecipePage.xaml?ID={0}", recipeID);

In the button click handler for the “pin” button, I first check to see if a tile for this page already exists, and if it doesn’t, I create it now. I create the tile using the current Recipe data: the image and the name. I also set a single static image—and static text—for the back of the tile. At the same time, I take the opportunity to repaint the button itself, using the “unpin” image. If, on the other hand, the tile did already exist, then I must be in the click handler because the user has chosen to unpin the tile. In this case, I delete the tile and repaint the button using the “pin” image, as shown in Figure 13.

Figure 13 Pinning and Unpinning Pages

private void PinUnpin_Click(object sender, RoutedEventArgs e)
{
  tile = ShellTile.ActiveTiles.FirstOrDefault(
    x => x.NavigationUri.ToString().Contains(thisPageUri));
  if (tile == null)
  {
    StandardTileData tileData = new StandardTileData
    {
      BackgroundImage = new Uri(
        thisRecipe.Photo, UriKind.RelativeOrAbsolute),
      Title = thisRecipe.Name,
      BackTitle = "Lovely Mangoes!",
      BackBackgroundImage =
        new Uri("Images/BackTile.png", UriKind.Relative)
    };
 
    ImageBrush brush = (ImageBrush)PinUnpin.Background;
    brush.ImageSource =
      new BitmapImage(new Uri("Images/Unpin.png", UriKind.Relative));
    PinUnpin.Background = brush;
    ShellTile.Create(
      new Uri(thisPageUri, UriKind.Relative), tileData);
  }
  else
  {
    tile.Delete();
    ImageBrush brush = (ImageBrush)PinUnpin.Background;
    brush.ImageSource =
      new BitmapImage(new Uri("Images/Pin.png", UriKind.Relative));
    PinUnpin.Background = brush;
  }
}

Note that if the user taps the pinned tile to get to the Recipe page, and then presses the phone’s hardware Back button, he will exit out of the application altogether. This is potentially confusing because the user normally expects that he will only exit the application when he presses Back from the main page, not from any other page. However, the alternative would be to provide some kind of “home” button on the Recipe page to allow the user to navigate back to the rest of the application. Unfortunately, this would also be confusing, because when the user gets to the main page and presses Back, he’d be back on the pinned Recipe page, instead of exiting out of the application. For this reason, although a “home” mechanism isn’t impossible to achieve, it’s behavior that you should weigh carefully before introducing.

Incorporate an XNA Game

Recall that I originally created the application as a Windows Phone Silverlight and XNA Application solution. This gave me three projects. I’ve been working with the main MangoApp project to build out the non-game functionality. The GameLibrary project acts as a “bridge” between the Silverlight MangoApp and the XNA GameContent. It’s referenced in the MangoApp project, and in turn references the GameContent project. This needs no further work. There are two main tasks required in order to incorporate a game into my phone application:

  • Enhance the GamePage class in the MangoApp project to include all the game logic.
  • Enhance the GameContent project to provide images and sounds for the game (no code changes).

Looking briefly at the enhancements that Visual Studio generated for a project that integrates Silverlight and XNA, the first thing to note is that the App.xaml declares a SharedGraphicsDeviceManager. This manages the sharing of the screen between the Silverlight and XNA runtimes. This object is also the sole reason for the additional AppServiceProvider class in the project. This class is used to cache the shared graphics device 
manager so it’s available to anything that needs it in the app, both Silverlight and XNA. The App class has an AppServiceProvider field, and it also exposes some additional properties for XNA integration: a ContentManager and a GameTimer. These are all initialized in the new InitializeXnaApplication method, along with a GameTimer, which is used to pump the XNA message queue.

The interesting work is how to integrate an XNA game within a Silverlight phone application. The game itself is actually less interesting. So, for this exercise, rather than spending effort writing a complete game from scratch, I’ll adapt an existing game—specifically, the XNA game tutorial on AppHub: http://msdn.microsoft.com/en-us/library/windowsphone/develop/ff472340(v=vs.105).aspx.

In my adaptation, I have a cocktail shaker, represented by the Player class in code, that fires projectiles at incoming mangoes (enemies). When I hit a mango, it breaks open and morphs into a mangotini. Every mango hit adds 100 to the score. Every time the cocktail shaker collides with a mango, player field strength is reduced by 10. When the field strength goes to zero, the game ends. The user can also end the game at any time by pressing the phone’s Back button, as expected. Figure 14 shows the game in progress.

The XNA Game in Progress
Figure 14 The XNA Game in Progress

I don’t need to make any changes to the (nearly empty) GamePage.xaml. Rather, all the work is done in the codebehind. Visual Studio generates starter code for this GamePage class, as described in Figure 15.

Figure 15 GamePage Starter Code

Field/Method Purpose Changes Required
ContentManager Loads and manages the lifetime of content from the content pipeline. Add code to use this to load images 
and sounds.
GameTimer In the XNA game model, the game performs actions when Update and Draw events are fired, and these events are governed by a timer. Unchanged.
SpriteBatch Used to draw textures in XNA. Add code to use this in the Draw method to draw the game objects (player, enemies, projectiles, explosions and so on).
GamePage Constructor Creates a timer and hooks up its Update and Draw events to OnUpdate and OnDraw methods. Keep the timer code, and additionally initialize the game objects.
OnNavigatedTo Sets up graphics sharing between Silverlight and XNA, and starts the timer. Keep the sharing and timer code, and additionally load content into the game, including any previous state from 
isolated storage.
OnNavigatedFrom Stops the timer and turns off XNA 
graphics sharing. Keep the timer and sharing code, and additionally store the game score and player health to isolated storage.
OnUpdate (Empty), handles the 
GameTimer.Update event. Add code to calculate game object changes 
(player position, number and position of enemies, projectiles and explosions).
OnDraw (Empty), handles the 
GameTimer.Draw event. Add code to draw game objects, game score and player health.

The game is a direct adaptation of the AppHub tutorial, which contains two projects: the Shooter game project and the ShooterContent content project. The content contains images and sound files. Although it doesn’t affect the application code, I can change these to align them with the mango theme of my application, and that’s just a question of replacing PNG and WAV files. The required (code) changes are all in the Shooter game project. Guidelines for migrating from the Game Class to Silverlight/XNA are on AppHub: http://channel9.msdn.com/Series/Get-to-Mango/Get-to-Windows-Phone-Mango-1-From-XNA-to-SLXNA.

First, I must copy the Shooter game project files into my existing MangoApp project. Also, I copy the ShooterContent content files into my existing GameContent project. Figure 16 summarizes the existing classes in the Shooter game project.

Figure 16 Shooter Game Classes

Class Purpose Changes Required
Animation Animates the various sprites in my game: the player, enemy objects, projectiles and explosions. Eliminate GameTime.
Enemy A sprite that represents the enemy objects that the 
user shoots. These will be mangoes in my adaptation. Eliminate GameTime.
Game1 The controlling class for the game. Merge into the GamePage class.
ParallaxingBackground Animates the cloud background images to provide a 3D parallax effect. None.
Player A sprite that represents the user’s character in the 
game. This will be a cocktail shaker in my adaptation. Eliminate GameTime.
Program Only used if the game targets Windows or Xbox. Unused; can be deleted.
Projectile A sprite that represents the projectiles that the player fires at the enemies. None.

In order to incorporate this game into my phone application, I need to make the following changes to the GamePage class:

  • Copy all fields from the Game1 class to the GamePage class. Also copy the field initialization in the Game1.Initialize method to the GamePage constructor.
  • Copy the LoadContent method, and all methods to add and update enemies, projectiles and explosions. None of these require any changes.
  • Extract all uses of the GraphicsDeviceManager to use a GraphicsDevice property instead.
  • Extract the code in the Game1.Update and Draw methods into the GamePage.OnUpdate and OnDraw timer event handlers.

A conventional XNA game creates a new GraphicsDeviceManager, whereas in a phone application I’ll already have a SharedGraphicsDeviceManager that exposes a GraphicsDevice property, and that’s all I really need. To simplify things, I’ll cache a reference to the GraphicsDevice as a field in my GamePage class.

In a standard XNA game, the Update and Draw methods are overrides of virtual methods in the base Microsoft.Xna.Framework.Game class. However, in an integrated Silverlight/XNA application, the GamePage class isn’t derived from the XNA Game class, so I must abstract the code from Update and Draw and insert it into the OnUpdate and OnDraw event handlers instead. Note that some of the game object classes (such as Animation, Enemy and Player), the Update and Draw methods, and some of the helper methods called by Update take a GameTime parameter. This is defined in Microsoft.Xna.Framework.Game.dll, and it should generally be considered a bug if a Silverlight application contains any reference to this assembly. The GameTime parameter can be completely replaced by the two Timespan properties—TotalTime and ElapsedTime—exposed from the GameTimerEventArgs object that’s passed in to the OnUpdate and OnDraw timer event handlers. Apart from GameTime, I can port the Draw code unchanged.

The original Update method tests GamePad state and conditionally calls Game.Exit. This isn’t used in an integrated Silverlight/XNA application, so it must not be ported to the new method:

//if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
//{
//    // this.Exit();
//}

The new Update method is now little more than a harness that calls into other methods to update the various game objects. I update the parallaxing background even when the game is over, but only update the player, enemies, collision, projectiles and explosions if the player is still alive. These helper methods calculate the number and positions of the various game objects. Having eliminated the use of GameTime, these can all be ported over unchanged—with one exception:

private void OnUpdate(object sender, GameTimerEventArgs e)
{
  backgroundLayer1.Update();
  backgroundLayer2.Update();
 
  if (isPlayerAlive)
  {
    UpdatePlayer(e.TotalTime, e.ElapsedTime);
    UpdateEnemies(e.TotalTime, e.ElapsedTime);
    UpdateCollision();
    UpdateProjectiles();
    UpdateExplosions(e.TotalTime, e.ElapsedTime);
  }
}

The UpdatePlayer method does need a little tweaking. In the original version of the game, when the player’s health dropped to zero, it was reset to 100, which meant that the game looped forever. In my adaptation, when player health drops to zero, I set a flag to false. I test for this flag in both the OnUpdate method and OnDraw. In OnUpdate, the flag value determines whether or not to compute further changes to the objects; in OnDraw, it determines whether to draw the objects or to draw a “game over” screen with the final score:

private void UpdatePlayer(TimeSpan totalTime, TimeSpan elapsedTime)
{
...unchanged code omitted for brevity.
 
  if (player.Health <= 0)
  {
    //player.Health = 100;
    //score = 0;
    gameOverSound.Play();
    isPlayerAlive = false;
  }
}

Play Along

In this article, I’ve looked at how to develop applications against several of the new features in Windows Phone SDK 7.1: local databases, LINQ to SQL, secondary tiles and deep linking, and Silverlight/XNA integration. The 7.1 release offers many more new features and enhancements to existing features.

The final version of the Mangolicious application is available on the Windows Phone Marketplace at bit.ly/nuJcTA (note: Zune software is needed for access). Note that the sample uses the Silverlight for Windows Phone Toolkit (a free download, available at bit.ly/qiHnTT).


Andrew Whitechapel* has been a developer for more than 20 years and currently works as a program manager on the Windows Phone team, responsible for core pieces of the application platform.*

Thanks to the following technical experts for reviewing this article: Nick GravelynBrian Hudson and Himadri Sarkar