×
Namespaces

Variants
Actions
Revision as of 09:26, 15 November 2012 by Vaishali Rawat (Talk | contribs)

Adding Windows Phone 8 features to your Windows Phone 7 application

From Nokia Developer Wiki
Jump to: navigation, search

Note.pngNote: This is a community entry in the Windows Phone 8 Wiki Competition 2012Q4.

In this article we are going to learn how to add some Windows Phone 8 functionality in an existing Windows Phone 7 application through the use of Reflection, and execute only when we are running under the correct operating system.

Contents

Introduction

Chances are you already have a popular app published for Windows Phone 7 and want to add new Windows Phone 8 features to it without having to release a separate version, creating fragmentation and losing all you hardly earned positive user reviews. We can achieve this by checking the current operating system version at runtime and then loading the appropriate assembly using Reflection to search for the specific types we need to use.

Limitations

We can only access new functions existing in the Microsoft.Phone assembly. Since the new Windows namespace is inside a WinRT component and these can't be reflected at the time being, accessing features like in-app purchases is impossible. If a method for doing this is discovered in the future, this wiki article will be accordingly updated.

Likewise, features that require new capabilities not available in Windows Phone 7 (like Wallet and removable storage) can't be used because the compiler will tell us that there is an unrecognised option specified in the application's manifest.

Creating a sample application

For this tutorial we are going to create a very simple application that only has one page, a TextBlock to display the operating system's version and four buttons, two for tasks already available in Windows Phone 7 and rest of the two for new tasks introduced in Windows Phone 8.

Specifying our viewmodel

The viewmodel (which is based on MVVM Light to simplify development) will have the following properties:

  • System.Version OsVersion: returns the value of System.Environment.OSVersion.Version.
  • bool IsWp8: returns true if OsVersion.Major equals 8.
  • bool CanLoadTypes: returns true if IsWp8 is true and the internal field wp8Assembly is not null (meaning that we could load the assembly without problems).

To store a reference to the assembly, we also need a private field of type System.Reflection.Assembly called wp8Assembly. We will wrap some helper functions around it so we don't need to publicly expose it. Now, let's fill in the constructor:

public MainViewModel()
{
// Load the assembly if we are in WP8.
if (this.IsWp8)
{
try
{
wp8Assembly = Assembly.Load(Wp8AssemblyFullName);
}
catch (Exception e)
{
MessageBox.Show("Couldn't load '" + Wp8AssemblyFullName + "' assembly.");
}
}
}

The full name of the target assembly is stored in the constant Wp8AssemblyFullName, and its value is Microsoft.Phone, Version=8.0.0.0, Culture=neutral, PublicKeyToken=24eec0d8c86cda1e. We will only load it if we are running under Windows Phone 8, thus circumventing the prohibition of referencing an assembly of a superior .NET version in case we did it via the Add Reference... command in the editor.

Now, we only need two helper functions to instantiate types stored in the loaded assembly:

public Type GetAssemblyType(string fullName)
{
return wp8Assembly.GetType(fullName);
}
 
public object CreateTypeInstance(Type type)
{
return wp8Assembly.CreateInstance(type.FullName);
}

These will come in handy when we modify the code behind of the page.

Modifying the page's XAML

As stated before, create one TextBox and four buttons in the page, either using Blend or the editor integrated in Visual Studio. If you used MVVM Light and modified the default MainViewModel class as stated, your viewmodel should be already registered in the ViewModelLocator class, allowing us to databind to it as if it were a singleton instance. So, set the Text property's value of your TextBox to {Binding Main.OsVersion} to display the operating system when running the application.

Next up, create four buttons and add different functions to their Click events. To prevent the user for launching Windows Phone 8 specific tasks under older system versions, set the IsEnabled property of the corresponding buttons to {Binding Main.IsWp8, Mode=OneWay}. It would be a good addition to create a converter that transforms the value of IsWp8 to a System.Windows.Visibility and bind it to the Visibility property to efficiently hide unavailable features to the end user.

Instantiating and launching the tasks

The final step is filling in the functions that will launch when each button is pressed. For the first two we are going to launch two tasks that have been available since Windows Phone 7, EmailComposeTask and WebBrowserTask:

private void MailTaskButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
EmailComposeTask composeTask = new EmailComposeTask();
composeTask.Show();
}
 
private void BrowserTaskButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
WebBrowserTask browserTask = new WebBrowserTask();
browserTask.Uri = new Uri("http://www.developer.nokia.com/");
browserTask.Show();
}

As you can see, there's nothing exceptional in this code. Now comes the part where we must use Reflection to extract the types needed. We have to follow these steps in each function that needs this:

  • First, we must check if CanLoadTypes is true, in case anything went wrong when initializing the viewmodel.
  • Search for the required Type using the GetAssemblyType helper method, and specify the full name. For example, for SaveAppointmentTask it would be Microsoft.Phone.Tasks.SaveAppointmentTask.
  • Instantiate it using CreateTypeInstance. Store the resulting value in a variable of type object.
  • Search for the desired member method by calling GetMethod in the previosly searched Type. Its only parameter is the name of the function, in our case Show. Store the resulting MethodInfo value.
  • In case you need to set the value of any property (like the case of MapsTask), call GetProperty in the Type using the property's name. This will return a PropertyInfo variable where you can call SetValue to assign its value.
  • Call the method Invoke of the MethodInfo previously obtained.
private void SaveAppointmentButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
// If we are in WP8
if (this.viewModel.CanLoadTypes)
{
// Instantiate a SaveAppointmentTask and call its Show method.
Type taskType = this.viewModel.GetAssemblyType(SaveAppointmentTaskTypeName);
object taskObject = this.viewModel.CreateTypeInstance(taskType);
MethodInfo showMethodInfo = taskType.GetMethod(ShowMethodName);
showMethodInfo.Invoke(taskObject, null);
}
}
 
private void SearchLocationButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
// If we are in WP8
if (this.viewModel.CanLoadTypes)
{
// Instantiate a MapsTask, set its SearchTerm property and call its Show method.
Type taskType = this.viewModel.GetAssemblyType(MapsTaskTypeName);
object taskObject = this.viewModel.CreateTypeInstance(taskType);
MethodInfo showMethodInfo = taskType.GetMethod(ShowMethodName);
PropertyInfo termPropertyInfo = taskType.GetProperty(SearchTermPropertyName);
termPropertyInfo.SetValue(taskObject, SearchTermValue, null);
showMethodInfo.Invoke(taskObject, null);
}
}

Now you can compile your project both from Visual Studio 2010 and Visual Studio 2012 and deploy it to Windows Phone 7 and Windows Phone 8 emulators/devices to test that it's running correctly.

Article Metadata
Code Example
Source file: File:WP8inWP7.zip
Compatibility
Platform(s): Windows Phone 7, Windows Phone 8
Article
Created: r2d2rigo (11 Nov 2012)
Last edited: Vaishali Rawat (15 Nov 2012)
42 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×