Accessing Windows Phone 7 Devices Hands-on Lab /

Hands-On Lab

Accessing Windows Phone 7 Devices

Lab version: 1.0.0

Last updated: 12/9/2010

Contents

Overview 3

Exercise 1: Capture Pictures Using the Camera Chooser 6

Task 1 – Capture an image 6

Task 2 – Display a captured image 12

Exercise 2: Load and Store Pictures 16

Task 1 – Save and load pictures to and from isolated storage 16

Task 2 – Save pictures to the pictures hub 24

Exercise 3: Using the Location Device and Bing Maps 27

Task 1 – Integrating GPS with Bing Maps 27

Task 2 – Assigning pictures with geographical locations 34

Task 3 – Displaying captured pictures on a Bing Map 37

Summary 41

Overview

The Windows Phone 7 is equipped with a Camera and GPS (global positioning system). Developers can leverage these devices to build location-aware applications and take live photos.

This lab walks you through the steps required to integrate your applications with the phone’s camera. The goal is to build an application that lets you capture pictures, give them a title, and save them to the application local store.

The lab also gives you the option to “fake” location and, when saving pictures to a local store, associate its latitude-longitude (lat-long) geo-coordinates, and create a view in which you can see the pictures on a map.

Objectives

At the end of the lab you will:

·  Be familiar with the Windows Phone 7 Camera Chooser API

·  Understand how to use the WP7 Location Device

·  Have saved pictures to the pictures hub

·  Have stored and loaded pictures and metadata from the Isolated Storage

·  Used Bing Maps control and services to fetch and display location data

·  Have created a simple map-based application with captured pictures

Prerequisites

The following is required to complete this hands-on lab:

·  Microsoft Visual Studio 2010 Express for Windows Phone or Microsoft Visual Studio 2010 (Microsoft Visual Studio 2010 Express for Windows Phone is part of the Windows Phone Developer Tools installation).

·  Windows Phone Developer Tools:

◦  http://www.microsoft.com/downloads/en/details.aspx?FamilyID=04704acf-a63a-4f97-952c-8b51b34b00ce&displaylang=en

◦  Silverlight for Windows Phone Toolkit (you can use the assemblies located in the assets folder): http://silverlight.codeplex.com/

·  Active Internet Connection

Note: If any of Microsoft.Phone.Controls.Toolkit or Microsoft.Expression.Interactions references are broken, you can remove them and add them again from the Assets folder which is part of this lab and can be found in <lab-folder>\Source\Assets\Libraries.

Setup

For convenience, much of the code used in this hands-on lab is available as Visual Studio code snippets.

To install the code snippets:

1.  Run the .vsi installer located in the lab's Source\Setup folder.

Note: If you have issues running the code snippets installer you can install the code snippets manually by copying all the .snippet files located in the Source\Setup\CodeSnippets folder of the lab to the following folder:

your-documents-folder>\Visual Studio 2010\Code Snippets\Visual C#\My Code Snippets

Using the Code Snippets

With code snippets, you have all the code you need at your fingertips. The lab document will tell you exactly when you can use them. For example,

Figure 1

Using Visual Studio code snippets to insert code into your project

To add this code snippet in Visual Studio, you simply place the cursor where you would like the code to be inserted, start typing the snippet name (without spaces or hyphens), watch as IntelliSense picks up the snippet name, and then press the Tab key twice when the snippet you want is selected. The code will be inserted at the cursor location.

Figure 2

Start typing the snippet name

Figure 3

Press Tab to select the highlighted snippet

Figure 4

Press Tab again to expand the snippet

To insert a code snippet using the mouse rather than the keyboard, right-click where you want to insert the code snippet, select Insert Snippet followed by My Code Snippets and then pick the relevant snippet from the list.

To learn more about Visual Studio IntelliSense Code Snippets, including how to create your own, see http://msdn.microsoft.com/en-us/library/ms165392.aspx.

Exercises

This hands-on lab comprises the following exercises:

2.  Capture pictures using Camera Chooser

3.  Load and Store pictures

4.  Using Location device and Bing Maps

Estimated time to complete this lab: 60 minutes.

Exercise 1: Capture Pictures Using the Camera Chooser

In this exercise you will:

·  Use the camera capture function to capture live pictures

·  Display captured pictures with their details

Task 1 – Capture an image

In this task you will use the camera capture chooser to capture a live image from both the WP7 emulator and device, and handle tombstoning situations while working with choosers.

Before you begin, please open the Source\Ex1 – CapturePictures\Begin.sln solution file, and review the code. The project is comprised of Models, Pages, Resources, the Application class, and the assets library.

Models in this case are passive data entities with no business logic. They are all derived from the NotifyingObject base class located in the AccessingWP7Devices.Assets project. The notifying object base class implements the .NET INotifyPropertyChanged interface for change notification, and provides minimal storage with generic get/set methods for holding the object’s state in a regular dictionary. In addition to models, there is a PictureRepository singleton object for handling and holding pictures. Currently the only thing it does is load the sample pictures, ResourcePicture, from the application resources into the pictures collection.

The Picture class represents a base class for captured pictures that you’ll create next, as well as for sample pictures located as resource in the resources folder.

To gain familiarity with the project, please build, deploy, and run it on the phone emulator.

Figure 5

First Run

The first page displays captured pictures. In our case, these are sample pictures for illustration. Clicking the camera app bar icon launches the Camera Capture built-in application, that let’s you take pictures. You’ll implement this as your first task. Clicking the map app bar icon navigates to the Bing Map page. Next you’ll add a pictures layer and set your real location on this map. Clicking the picture app bar icon navigates to the pictures slide show, where you can start a slide show of the pictures you’ve captured.

5.  To capture a picture, use the camera capture chooser. Open the PictureListPage.xaml.cs file and add a new field for holding the camera capture task.

Note: To ensure that your application receives the result of the Chooser task when your application is reactivated, the Chooser object must be defined within a global scope of the page and you must initialize the Chooser and assign the Completed event delegate in the page’s constructor.

You can read more about the Launchers and Choosers Hands-on-Lab.

C#

private readonly CameraCaptureTask _cameraTask;

6.  Initialize the camera task in the page’s constructor and register its Completed event.

C#

public PictureListPage()

{

DataContext = PictureRepository.Instance;

InitializeComponent();

_cameraTask = new CameraCaptureTask();

_cameraTask.Completed += cameraTask_Completed;

}

private void cameraTask_Completed(object sender, PhotoResult e)

{

}

Note: We want to display the camera task as first option when the camera app bar icon Is clicked.

7.  In the ApplicationBarNewPicture_Click event handler, call the camera chooser Show method.

C#

private void ApplicationBarNewPicture_Click(object sender, EventArgs e)

{

_cameraTask.Show();

}

Note: The camera capture task completion event argument contains both the captured picture temporary file name and a temporary picture stream. To create a picture using these properties and holding additional metadata you should create a special model class.

8.  Add a new class called CapturedPicture to the project’s Model folder.

9.  Add the DataContractAttribute attribute to the class so you can serialize it later for tombstoning.

C#

[DataContract]

public class CapturedPicture

{

}

10.  Create a public property of the type byte[], named ImageBytes for holding the picture bytes and decorate it using the DataMemberAttribute attribute.

11.  Create a public property of the type string, named FileName for holding the picture file name and add the DataMemberAttribute attribute.

C#

[DataContract]

public class CapturedPicture

{

[DataMember]

public byte[] ImageBytes

{

get;

set;

}

[DataMember]

public string FileName

{

get;

set;

}
}

12.  Derive the CapturedPicture class from the Picture base class and override the CreateBitmapSource method to return a new WriteableBitmap using the picture bytes.

Note: To create a WriteableBitmap from a stream use the PictureDecoder.DecodeJpeg helper method.

C#

[DataContract]

public class CapturedPicture : Picture

{

protected override BitmapSource CreateBitmapSource()

{

BitmapSource source = null;

if (ImageBytes != null)

{

using (var stream = new MemoryStream(ImageBytes))

{

source = PictureDecoder.DecodeJpeg(stream);

}

}

return source;

}

}

13.  Create a default constructor and a constructor that has two parameters: one for the file name and the second for the picture stream. Set the ImageBytes property with the stream bytes. Set the FileName property with the short file name without the path. Set the Picture.DateTaken property to DateTime.Now as a long date string.

C#

[DataContract]

public class CapturedPicture : Picture

{

public CapturedPicture()

{

}

public CapturedPicture(string capturedFileName, Stream capturedImageStream)

{

ImageBytes = ReadImageBytes(capturedImageStream);

DateTaken = DateTime.Now.ToLongDateString();

FileName = System.IO.Path.GetFileName(capturedFileName);

}

private byte[] ReadImageBytes(Stream imageStream)

{

byte[] imageBytes = new byte[imageStream.Length];

imageStream.Read(imageBytes, 0, imageBytes.Length);

return imageBytes;

}

}

14.  Now you are ready to handle the camera capture task. In the cameraTask_Completed event handler located in the PictureListPage class, check to confirm that the task completed successfully; if so, create an instance of the type CapturedPicture using the event arguments OriginalFileName and ChosenPhoto.

C#

private void cameraTask_Completed(object sender, PhotoResult e)

{

if (e.TaskResult == TaskResult.OK)

{

var capturedPicture = new CapturedPicture(e.OriginalFileName, e.ChosenPhoto);

}

}

Note: Opening a chooser causes the application to be deactivated. When a chooser finishes its job, the application is reactivated. Hence we should save the transient state (the captured picture in this case) before leaving the chooser and reload it when the application is reactivated.

15.  To save the CapturedPicture instance, use the TransientState.Set<T> method. The TransientState type is a helper class located in the assets project. It simply wraps calls to the Microsoft.Phone.Shell.PhoneApplicationService helper class, which handles the phone’s transient state, with generic get/set methods.

C#

private void cameraTask_Completed(object sender, PhotoResult e)

{

if (e.TaskResult == TaskResult.OK)

{

var capturedPicture = new CapturedPicture(e.OriginalFileName, e.ChosenPhoto);

TransientState.Set("capturedPicture", capturedPicture);

}

}

Note: Clicking Back while the camera chooser is active, closes the chooser and navigates back to the application directly to the last page vider vby the user. In such cases, there may be no picture at all. If so, we want stay on the same page if we have a picture to display. Otherwise, we want to navigate to the captured picture details page.

16.  To load the captured picture at the moment the page is loaded, override the Page.OnNavigatedTo method and use the TransientState helper class to restore the captured picture state.

Note: When calling the TransientState.Get<T> method, make sure you pass ‘false’ as the last argument so that the captured picture is not removed from the state. You’ll extract it again later.

C#

protected override void OnNavigatedTo(NavigationEventArgs e)

{

var capturedPicture = TransientState.GetCapturedPicture>("capturedPicture");

base.OnNavigatedTo(e);

}

17.  Now that you’ve extracted the captured picture from the transient state, check if it is not null, then pass this state to the CapturedPicturePage page just before navigating to it (use TransientState.Set<T> and the CapturedPicturePage.ModelStateKey key that is expected by CapturedPicturePage); then navigate to the CapturedPicturePage.xaml page.

Note: You can use the NavigationServiceExtensions.NavigateTPage extension method with the relevant page type to easily navigate to the required page.

C#

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)

{

var capturedPicture = TransientState.GetCapturedPicture>("capturedPicture");

if (capturedPicture != null)

{

TransientState.Set<CapturedPicture>(CapturedPicturePage.ModelStateKey, capturedPicture);

NavigationService.NavigateCapturedPicturePage>();

}

base.OnNavigatedTo(e);

}

18.  To test the results, build and run the application. Click the camera icon in the app bar to open the camera capture chooser. Take a shot and click accept. The CapturedPicturePage opens.

Figure 6

Capture a Picture

19.  To test the phone’s Back button while the camera chooser is opened, go back to the main page, capture a picture, and now click Back. This should return to the main page.

Task 2 – Display a captured image

In this task you will create a simple view for displaying the captured picture, and provide a place for collecting user notes and displaying the date the picture was taken.

1.  To display the captured picture you should first extract the captured picture from the transient state, stored in Task 1. Open the CapturedPicturePage.xaml.cs file and add a new get property (this property will not have any setter) of the type CapturedPicture named Model.

C#

private CapturedPicture Model

{

get;

}

2.  Implement the Model property by getting the value from the page’s DataContext. You’ll use this later to bind the page’s control with the picture. First check if DataContext is null; if so try to extract the picture from the transient state set by the previous page. If it is still null, set the DataContext with a fresh instance of the type CapturedPicture.

C#

private CapturedPicture Model

{

get

{

if (DataContext == null)

{

var model = TransientState.GetCapturedPicture>(ModelStateKey);

if (model == null)

{

model = new CapturedPicture();

TransientState.Set(ModelStateKey, model);

}

DataContext = model;

}

return DataContext as CapturedPicture;

}

}

3.  Override the Page.OnNavigatedTo and call the Model property. You’ll code to this method later.

C#

protected override void OnNavigatedTo(NavigationEventArgs e)