Sharing Data Across Pages on Windows Phone
Most Windows Phone applications (and for that matter Windows 8 applications too) will quickly evolve to include more than one page. Very simple “utility” apps like calculators might get away with a single page, but even applications that fit a bunch of information on one screen using a Panorama will eventually end up navigating to a second screen when the user taps on something. Single page applications are simple because all of the data is in one place. As soon as a second page gets added to the application the question always comes up “How do I share data between pages?”
Windows Phone has at least three different recommended options for sharing data across pages and I’ll cover all three in this article. These tactics will apply to Windows 8 too, but I’ll wait until after the beta to see if there’s anything special to add here for Windows 8.
The first option for sharing data is to pass it as part of the query string when you navigate to the page. If you’ve done any web development before this method should feel right at home. On Windows Phone, to navigate from Page1 to Page2, you write code like this:
But what you might not realize is that you can also pass parameters as part of the navigation like this:
Now the parameters ‘ProductId’ and ‘Rating’ are being passed to page2.
The next question, obviously, is how do to receive those parameters on page2. that is accomplished by overriding a special method on the page class called OnNavigatedTo. In our example above we would write something like this:
There are some important things to notice here. First, the page grabs these values through a special object called the NavigationContext. Second, I’m not showing it here but these named values aren’t guaranteed to exist so we really should check for them before we try to use them. And finally, the only type of data we can pass this way are strings. That’s why we have to use int.Parse for the rating value.
Query string parameters work well for simple values. In fact query string parameters are how data gets passed into your application when it’s launched from a toast or from secondary tiles. Query string parameters can be pretty restrictive though, since they can’t be used to pass around objects (classes). Let’s take a look at a fairly common scenario which would be difficult to handle with query strings alone.
Let’s say we’re building a game and our game has three pages:
- MainPage – Where the main menu to start a new game, watch the credits, view the high score, etc.
- GamePage – The page where the user actually plays the game. This may be a Silverlight / XNA hybrid page or it could be just Silverlight.
- HighScorePage – A page that shows the score rankings and the initials of the top players.
At first you may not think these pages need to share data, but think for a moment about how high score systems work. Obviously HighScorePage needs the data to be able to show it, but GamePage will also need the data to be able to notify the user when they’ve beat a high score and ask them to enter their initials. Even MainPage might want access to score data to be able to show the top player.
Whenever I see this sort of pattern I stop and ask myself if it makes sense to provide the data as a service. Now, ‘service’ tends to be an overloaded term in programming so let me be clear that what I’m talking about is a simple reusable component. (For more info see Service Orientated Architecture or SOA.)
If I was going to keep track of high scores as a service I’d probably make a simple class to represent a single score:
And then I’d make a simple ‘service’ class for managing the scores:
What’s neat about making this a service is we’ve hidden the work of loading, saving and updating high scores in a single place. So today we can store high scores locally as XML and tomorrow we could change to storing high scores on a server and sharing them across devices. The only code that would need to change would be inside of HighScoreService and the rest of the application would work exactly the same.
Now that we’ve created our High Score service, how do we share it across pages? There are two easy ways to do this on Windows Phone.
The first option is to add the service as a property of the Application. Every Windows Phone project has a file called App.xaml.cs (it’s hidden under App.xaml in the Solution Explorer). Inside of App.xaml.cs you’ll find something like this:
So every project has a class called ‘App’ that inherits from Application. You can add any properties you want to this class and they will be available on every page. So, we could add our service to our Application like this:
Then we could get to it on any page like this:
Let me explain the slightly ugly syntax there. Application.Current can be used from any code to get access to the currently running application instance. Unfortunately, what we get back is the generic Application base class so we have to cast it to the App version that’s part of our project before we can see our custom properties.
The second way we can share our high score service around our application is to make it a singleton. Making a class a singleton is basically saying “there can only ever be one of these things in existence at any time”. The way you implement it in .NET is like this:
- Make all of the constructors private (if there is no constructor add a default one and make it private)
- Make a static public property on the class called ‘Instance’ that returns the class itself.
- Inside the “getter” of the property, check a static private variable to see if the instance has already been created.
- If the instance hasn’t been created, create it. Otherwise return the existing instance.
Therefore our High Score Service converted to a singleton would look like this:
The code to access this service from any page would then look like this:
Or even more simply:
So which pattern is better (adding the service as a property of the App class or making it a singleton)? Most of the time it comes down to a matter of preference. I personally think the “instance” code inside a singleton class make it a little uglier, but I also think the singleton pattern looks cleaner throughout the rest of the codebase. On the other hand, when you expose services as properties on the App class that gives the App a chance to create those services and potentially wire one service up to another. If you start finding yourself with a lot of services in a single application, especially services that depend on each other, you really should look into something like the Managed Extensibility Framework (MEF) or Unity to help you manage the services and dependencies.