Share via


Exercise 3: Persisting the State of the Game Using Isolated Storage

In this exercise, you update the application to save its state so that you can resume the game the next time you open it. To implement this, you use Isolated Storage.

Isolated Storage enables managed applications to save and retrieve information from a local store. This architecture is very similar to the one used in Silverlight 4. All I/O operations are restricted to the scope of the Isolated Storage; they do not have direct access to the underlying operating system file system.

Some of the benefits of using Isolated Storage are data protection from other applications, quota management, and blinders that ensure applications deal solely with their own data.

Task 1 – Adding Assembly References and Other Assets

To take advantage of Isolated Storage, you need to add a provided helper file and an assembly reference to the project.

  1. If you completed the steps in the previous exercise, you may continue with the solution that you created for that exercise; otherwise, open Begin.sln from Ex3-UsingIsolatedStorage\Begin in the Source folder of the lab.
  2. Add a reference to the System.Servicemodel.Web assembly:
    • Right-click the References folder in Solution Explorer, select Add Reference, select the .NET tab, select the System.Servicemodel.Web assembly from the list of components and click OK

      Note:
      The System.Servicemodel.Web assembly contains the DataContractJsonSerializer that the application uses to serialize objects using JavaScript Object Notation (JSON) before persisting them in Isolated Storage.

  3. Now, add a helper class to the project to handle Isolated Storage:
    • Right-click the project in Solution Explorer, point to Add, select Existing Item, browse to Assets in the Source folder of the lab, select IsolatedStorageHelper.cs and then click Add
      Note:
      The IsolatedStorageHelper class contains methods to handle the serialization of objects to and from Isolated Storage. The provided class contains several method stubs that you will implement later in this exercise.

Task 2 – Updating the Puzzle UI

In this task, you update the game page to provide three buttons that allow users to load, save, and delete the state of the game. For this purpose, you modify the XAML markup of the user interface to define the necessary elements and then create event handlers for each button. Finally, you implement the required methods in the IsolatedStorageHelper class to load, save, and delete serialized objects from Isolated Storage.

  1. Double-click PuzzlePage.xaml in Solution Explorer to open the page that contains the UI of the game.
  2. Switch to the XAML view. To change the view and maximize the viewing area, double-click the XAML tab on the right edge of the designer window. If you have trouble identifying the correct tab, position the mouse cursor over each tab to display a tooltip that identifies it.

    Note:
    If you configured the designer to show a horizontal split view, the tabs are located on the bottom edge of the window.

  3. Insert the following (highlighted) XAML markup immediately after the last TextBlock element named TapToContinueTextBlock.

    XAML

    ... <Grid x:Name="LayoutRoot" Background="Transparent"> <StackPanel Orientation="Vertical" VerticalAlignment="Top" Grid.Row="1"> <Border x:Name="CongratsBorder"...> ... </Border> <Border x:Name="border"...> ... </Border> <TextBlock x:Name="TapToContinueTextBlock" HorizontalAlignment="Center" Text="Tap the picture to start the puzzle" TextWrapping="Wrap" Foreground="#FFD0D0D0" FontSize="17.333"/> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" > <Button x:Name="LoadButton" Content="Load" Margin="10" /> <Button x:Name="SaveButton" Content="Save" Margin="10" /> <Button x:Name="ClearStorageButton" Content="Clear" Margin="10" /> </StackPanel> </StackPanel> </Grid> ...

    Note:
    The added XAML markup adds three buttons that will load, save, and clear the data stored in Isolated Storage.

  4. Switch to Design view to see the changes to the user interface after adding the new buttons. To do this, double-click the Design tab on the right edge of the designer window.
  5. Now define an event handler for each button: Click the button labeled “Load” on the designer surface to select it and then press F4 to open its Properties window.
  6. In the Properties window, click the Events tab to display a window with a list of available events and then find the Click event in this list and type LoadButton_Click in the text box located next to this event. After that, press ENTER to generate an event handler with this name and open the code-behind file to display the method stub generated by Visual Studio
  7. Insert the following (highlighted) code into the body of the LoadButton_Click event handler:

    C#

    private void LoadButton_Click(object sender, RoutedEventArgs e) { var gameState = IsolatedStorageHelper.GetObject<PuzzleState>("PuzzleState"); if (gameState == null) { MessageBox.Show("Sorry, no game state found.", "Oops!", MessageBoxButton.OK); } else { // set game state this.game.SetState(gameState); } }

  8. Next, right-click the code editor window and select View Designer to switch back to Design view. Click the button labeled “Save” on the designer surface to select it and then press F4 to open its Properties window.
  9. In the Properties window, click the Events tab, then find the Click event and type SaveButton_Click in the text box located next to this event. Press ENTER to generate an event handler with this name and open the code-behind file to display the method stub generated by Visual Studio.
  10. Insert the following (highlighted) code into the body of the SaveButton_Click event handler:

    C#

    private void SaveButton_Click(object sender, RoutedEventArgs e) { // save game state PuzzleState gameState = this.game.GetState(); IsolatedStorageHelper.SaveObject("PuzzleState", gameState); }

  11. Once again, right-click the code editor window and select View Designer to switch back to Design view. Click the button labeled “Clear” on the designer surface to select it and then press F4 to open its Properties window.
  12. In the Properties panel, click the Events tab, find the Click event, and then type ClearStorageButton_Click in the text box located next to this event. Press ENTER to generate an event handler with this name and open the code-behind file to display the method stub.
  13. Insert the following (highlighted) code into the body of the ClearStorageButton_Click event handler:

    C#

    private void ClearStorageButton_Click(object sender, RoutedEventArgs e) { // remove state and image IsolatedStorageHelper.DeleteObject("PuzzleState"); }

  14. Now, double-click IsolatedStorageHelper.cs in Solution Explorer to open this file.
  15. Find the GetObject<T> method and replace its body with the following (highlighted) code:

    C#

    public static T GetObject<T>(string key) { if (IsolatedStorageSettings.ApplicationSettings.Contains(key)) { string serializedObject = IsolatedStorageSettings.ApplicationSettings[key].ToString(); return Deserialize<T>(serializedObject); } return default(T); }

    Note:
    The GetObject<T> method retrieves an object from isolated storage given its key. It takes advantage of the IsolatedStorageSettings class that stores a dictionary of key-value pairs in isolated storage. Objects are stored in serialized format using the DataContractJsonSerializer provided in the System.ServiceModel.Web assembly, which serializes objects to the JavaScript Object Notation (JSON) and deserializes JSON data to objects.

  16. Next, insert the following (highlighted) code into the body of the SaveObject<T> method:

    C#

    public static void SaveObject<T>(string key, T objectToSave) { string serializedObject = Serialize(objectToSave); IsolatedStorageSettings.ApplicationSettings[key] = serializedObject; }

    Note:
    The SaveObject<T> method stores an object to isolated storage given its key. The key can then be used to retrieve the object back from storage.

  17. Finally, implement the DeleteObject<T> method using the following (highlighted) code:

    C#

    public static void DeleteObject(string key) { IsolatedStorageSettings.ApplicationSettings.Remove(key); }

    Note:
    The DeleteObject method removes an object from isolated storage given its key.

Task 3 – Verifying

In this task, you will build and run the completed application in the Windows Phone Emulator. To test the use of Isolated Storage, you start a new game and move some of the pieces in the puzzle. After that, you save the state of the game and close it. Then, you launch the application one more time and restore the saved state to restore the game to the same condition that it had before you closed the application.

  1. To test the latest changes, press F5 to build and deploy the application to the emulator once again. Wait for the splash screen to appear, then click START, and tap the screen to begin a new game.
  2. On the game page, click Load to attempt to restore any saved state. Notice that, predictably, this results in an error message indicating that no game state was found. Click ok to dismiss the error message.

    Figure 21

    Load operation fails when there is no previous state

  3. Drag some of the pieces of the puzzle on the board.

    It is best if you can arrange one or more of the pieces into a pattern that you can easily remember. This will make it easier to determine whether you obtain the same pattern after you reload the game state later on.

  4. Click Save to store the current state of the game.
  5. Now, continue moving the pieces until you obtain a different arrangement, but do not save it.
  6. Once again, click Load to restore the previously saved state. Notice that this time, the position of the pieces on the board changes, restoring the same pattern that the board had when you originally saved the game state.
  7. Click the Back button () in the emulator window to navigate to the home page that contains the splash screen. Then, click the Back button again to exit the application and display the Quick Launch menu.
  8. Now, restart the application from the Quick Launch menu. To do this, click the arrow button to “All Applications.

    Figure 22

    Accessing “All Applications” in the Quick Launch menu

  9. In the list of installed applications, click the entry for WindowsPhonePuzzle to start the application once again.

    Figure 23

    Launching the application from the Quick Launch menu

    Note:
    Visual Studio detaches the debugger whenever you exit the application. The application image remains loaded in the emulator and you can restart it. Note, however, that when you do this the application no longer runs under the debugger.

  10. Click START to begin a new game and then, in the game page, click Load to restore the previously saved state. Verify that the board pattern matches the one saved before you exited the application demonstrating that isolated storage is preserved even after you exit the application.
  11. Click Clear to erase the saved state from Isolated Storage.
  12. Now, click Load once again and notice that you receive the same error message that you saw initially, indicating that you have successfully cleared the saved state.