How to add Windows Phone 8 builds to your existing apps

With the release of Windows Phone 8, Microsoft introduced a number of new features for developers to use in their apps. Aside from these new features, there have also been quite a few improvements to the platform such as support for WXGA (768 × 1280) and 720p (720 × 1280) resolutions and the inclusion of the Panorama, Pivot and LongListSelector controls in the ROM of the OS. This article will provide a step-by-step guide on how to add Windows Phone 8 builds to your existing apps and will also list some tips on how to solve a few common challenges you may face while doing so.

Our sample project

My Phone App Windows Phone 7

I created a small sample app to add a Windows Phone 8 build to (you’ll find the download link at the bottom of this post: MyPhoneApp_Start.zip. Note that you need to download the NuGet packages referenced in the project after downloading). It’s a basic Panorama app that get my latest 10 tweets from Twitter and lists them on the first panorama panel. It’s using an MVVM architecture, which gives us a representative solution to work with.

One of the things worth noting is that I’m using Microsoft.Bcl.Async NuGet package to use the async/await pattern in my Windows Phone app. I also created a Downloader class that gives me an easy way to access the DownloadStringAsync method from the WebClient object with the async/await pattern (based on John Thom’s work at http://johnthom.com/making-a-windows-runtime-wrapper-for-webclient/. Take a look at the implementation before we move on.

Restructuring our solution

This step isn’t mandatory, but I prefer doing it so there’s some more structure in the solution. The basic idea is to move all our code that can be used from both our existing Windows Phone 7 app as well as the Windows Phone 8 build, which we will add soon, to a Common project in the solution. The bad thing about this approach is that we have to create the Common project as a Windows Phone 7 class library, which will be used in our Windows Phone 8 build. I haven’t really noticed any negative impact of this decision in my existing apps, but note that you will be referencing a Windows Phone 7 library in your Windows Phone 8 build. I’ll explain later how we can get around this issue, if you don’t mind sacrificing a bit of maintainability.

One of the things I like to do when creating a Common project in my solution is to use the same (default) namespace as the Windows Phone 7 app. This will help us a little in re-using our existing XAML and CS files.

Common Project Namespace

Here’s the steps we need to take to move our app’s logic to a new Common project:

  1. Add a new Windows Phone 7 class library project to the solution
  2. Move our Converters, Helpers, Models, Resources and ViewModels folders to the Common project
  3. Remove the Json.NET, SharpGIS.GZipWebClient and Microsoft.Bcl.Async NuGet packages from the app project and add them to the Common project
  4. Change the XML namespace declarations in App.xaml to reference the Common project:

From:

    xmlns:c="clr-namespace:MyPhoneApp.Converters"
    xmlns:h="clr-namespace:MyPhoneApp.Helpers"

To:

    xmlns:c="clr-namespace:MyPhoneApp.Converters;assembly=MyPhoneApp.Common"
    xmlns:h="clr-namespace:MyPhoneApp.Helpers;assembly=MyPhoneApp.Common"

After these changes, our project should build and run as it did before adding the Common project. The difference now obviously being having a re-usable class library that contains everything but the Views of the app. You can download the solution that contains the Windows Phone 7 and Common projects at the bottom of this post: MyPhoneApp_Common.zip.

Adding a Windows Phone 8 build

Now that we have our Common project in place, we can add our Windows Phone 8 build. We’ve solved the challenge of re-using our app logic by moving it to the Common project, which we’ll reference in our Windows Phone 8 project, but we still have some challenges to solve:

  • Supporting the new screen resolutions
  • Using the native Panorama control in the ROM
  • Using the Windows Phone 8 async/await pattern (Microsoft.Bcl.Async is not needed anymore)
  • Fixing our App.xaml and App.xaml.cs files

The first thing we’ll do is add a Windows Phone 8 project to our solution. This can be a default Windows Phone app, as we’re going to re-use the files from our Windows Phone 7 and Common projects, but make sure you target Windows Phone 8.0 when adding this project. Go ahead and remove the Resources folder and the LocalizedStrings.cs and MainPage.xaml (and associated MainPage.xaml.cs) files. Also reference our Common project, so we can use the functionality that’s in there.

Supporting the new screen resolutions

Because we now have a Windows Phone 8 project, which will create a Windows Phone 8 build, we can support the new screen resolutions. One of the things we can do is recreate our pages in the Windows Phone 8 project, if we want to make them different from our Windows Phone 7 app, but if that’s not a requirement it’s easier to link to the files in our Windows Phone 7 project. We can either do this by holding Alt on the keyboard and dragging the Views folder from our Windows Phone 7 project to our Windows Phone 8 project. We can also manually create the Views folder in our Windows Phone 8 project and add the files by right-clicking the new Views folder, choosing Add->Existing Item… and navigating to the Windows Phone 7 project Views folder and selecting Add As Link (refer to the two screenshots below).

Add Existing Item Add As Link

If you decided earlier on you don’t want to use a Common project based on Windows Phone 7, you can use this same technique to link all the files that are in the Common project from the Windows Phone 7 project to the Windows Phone 8 project.

Using the native Panorama control in the ROM

The Panorama, Pivot and LongListSelector controls, which were previously available in libraries outside of the base ROM are now included in the platform. This means that they now benefit from improved performance due to the changed threading structure. If we want to keep re-using our MainPage.xaml, we will have to solve the namespace issue this introduces. Right now we have the namespace for our Panorama defined as:

xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"

In Windows Phone 8, the controls are moved to the Microsoft.Phone assembly, leaving the namespace intact. Unfortunately, XAML does not support conditional compilation directives yet (more on this later), so we’ll have to find another solution. One of the things you can do is introduce a custom SharedControls class, where you inherit the controls from the Microsoft.Phone.Controls namespace:

    public class Pivot : Microsoft.Phone.Controls.Pivot
    { }
    public class PivotItem : Microsoft.Phone.Controls.PivotItem
    { }
    public class PivotHeadersControl : Microsoft.Phone.Controls.Primitives.PivotHeadersControl
    { }

    public class Panorama : Microsoft.Phone.Controls.Panorama
    { }
    public class PanoramaItem : Microsoft.Phone.Controls.PanoramaItem
    { }

    public class LongListSelector : Microsoft.Phone.Controls.LongListSelector
    { }

Note that this is not something you can include in the Common project, as that project compiles to a Windows Phone 7 library, so we’ll add this SharedControls class to our Windows Phone 7 project and link to it from our Windows Phone 8 project. Now we should rename the namespace in our MainPage.xaml for the Panorama control to our own namespace and we’ll use the native Panorama control in our Windows Phone 8 build.

Using the Windows Phone 8 async/await pattern

Currently we’re using the Microsoft.Bcl.Async NuGet package to provide us with the async/await functionality in our Windows Phone 7 app (or rather, our Common project). Because we compile our Common project as a Windows Phone 7 library, this setup will work for us as is, but if you decided not to use the Common project approach, you need to make a change to the Downloader helper class on line 15:

            await TaskEx.Run(() =>

In Windows Phone 8, the TaskEx class is simply called Task. We’ll use compiler directives to conditionally use the TaskEx or Task classes. First we’ll need to add an additional compilation symbol to our Windows Phone 7 and Windows Phone 8 projects to distinguish between them. Right-click on the project and select Properties. Select Build on the left side and you’ll see the current conditional compilation symbols: SILVERLIGHT;WINDOWS_PHONE. Change this to include a new one for both projects (e.g. SILVERLIGHT;WINDOWS_PHONE;WP7 and SILVERLIGHT;WINDOWS_PHONE;WP8).

Conditional Compilation Symbols

Once we’ve added the new conditional compilation symbols, we can use PRAGMA statements to do the conditional compilation. In the example of the Downloader helper class, this will look like:

            await
#if WP7
                TaskEx
#elif WP8
                Task
#endif
                .Run(() =>

Fixing our App.xaml and App.xaml.cs

Linking or sharing the App.xaml isn’t desired, as there are fundamental differences in the OS versions that we might want to use in the App.xaml/App.xaml.cs. However, if we change the default namespace in our Windows Phone 8 project to be MyPhoneApp as well as the Common project, our code sharing solution becomes a bit easier. In the Windows Phone 8 template there’s a default implementation for Localization. One of the things that’s also included in the App.xaml.cs is the InitializeLanguage method, where some of the language logic is initialized. We’ll have to change the class that’s used in this method to our localization class (in this case changing AppResources to LanguageResources).

At this point we can run our Windows Phone 8 build in the 720p emulator and notice no black border on top. Success! You can download the final solution at the end of this post as well.

My Phone App Windows Phone 8

Some additional tips

Some additional points, from personal experience, you might want to consider:

Downloads

MyPhoneApp_Start.zip
MyPhoneApp_Common.zip
MyPhoneApp_End.zip