Sie sind auf Seite 1von 73

Hands-On Lab

Using Bing Maps


Lab version: Last updated: 1.0.0 11/5/2013

Push Notifications Hands-on Lab

CONTENTS

Overview.......................................................................................................................................... 3 Exercise 1: Introduction to the Bing Map Control ........................................................................... 7 Task 1 Registering a Bing Maps Account .............................................................................. 7 Task 2 Working with the Bing Map Control........................................................................ 10 Exercise 2: Handling and Customizing Pushpins ........................................................................... 30 Task 1 Creating a Pushpins Layer........................................................................................ 30 Task 2 Creating a Pushpins Catalog .................................................................................... 40 Exercise 3: Calculating a Route ...................................................................................................... 50 Task 1 Adding a Route to the Map ..................................................................................... 50 Task 2 Displaying Route Itineraries..................................................................................... 61 Summary........................................................................................................................................ 73

Page | 2

Push Notifications Hands-on Lab

Overview
The Bing Maps Silverlight Control for Windows Phone combines the power of Silverlight and Bing Maps to provide an enhanced mapping experience. Developers can use the Bing Maps Silverlight Control to incorporate the latest location and local search features into their Windows Phone applications. Using both Bing Maps Silverlight Control and the Bing Maps SOAP (strategy on a page) Services, you can create Windows Phone applications that include an enhanced mapping experience. This lab walks you through the steps required for using the Bing Maps Silverlight Control for Windows Phone, and provides a quick reference for developing Windows Phone applications integrated with Bing Maps.

Objectives
Upon completion of the lab you will: Be familiar with Bing Maps for Windows Phone Understand how to use Bing Map control with Data Binding Have used Bing Maps services to fetch mapping data Have created a simple map-based application, complete with pushpins and route layers

Prerequisites
The following is required to complete this hands-on lab: Microsoft Visual Studio 2010 Express for Windows Phone or Microsoft Visual Studio 2010 Windows Phone Developer Tools Active Internet Connection Note: You can download all Windows Phone development tools in one package from http://developer.windowsphone.com

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

Push Notifications Hands-on Lab

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.

Page | 4

Push Notifications Hands-on Lab

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: 1. Introduction to the Bing Map Control Page | 5

Push Notifications Hands-on Lab

2. Handling and Customizing Pushpins 3. Calculating and Rendering a Route

Estimated time to complete this lab: 90 minutes.

Page | 6

Push Notifications Hands-on Lab

Exercise 1: Introduction to the Bing Map Control


In this exercise you will: Register a Bing Maps account to get a private key Learn about the Bing Silverlight map control for Windows Phone Add a map control to the page Attach the map control with Bing Maps private key Switch between aerial and road map modes Center and zoom the map to a geographic location

You will use the Microsoft Visual Studio 2010 Express for Windows Phone development environment, and will deploy to the Windows Phone Emulator for debugging. The solution we will be working with is based upon the Silverlight for Windows Phone Application template. Note: The steps in this hands-on lab illustrate procedures using Microsoft Visual Studio 2010 Express for Windows Phone, but they are equally applicable to Microsoft Visual Studio 2010 with the Windows Phone Developer Tools. Instructions that refer generically to Visual Studio apply to both products.

Task 1 Registering a Bing Maps Account In this task you will create a Bing Maps account over the Internet. The Bing Maps Account Center allows you to create keys to use the Bing Maps Control, Bing Maps SOAP Services, Bing Maps REST (representational state transfer) Services and Bing Spatial Data Services. If you already have a key for using Bing, you may use it for the next tasks. Without a valid key, you wont be able to see retrieve Bing Maps content from the web. 1. Open your web browser and go to the following address: http://www.bingmapsportal.com. 2. Click Create to create a new Bing Maps account using your Windows Live ID.

Page | 7

Push Notifications Hands-on Lab

Figure 5 Bing maps registration

3. On the next page, fill in your details.

Figure 6 Bing maps account details

4. Once youve agreed the terms and registered and/or signed in, you may choose to create a new key for your application. Click the Create or view keys link on the left.

Page | 8

Push Notifications Hands-on Lab

Figure 7 Create or view keys

5. On the next page fill in your application details and click Createkey.

Figure 8 Create a new key

Page | 9

Push Notifications Hands-on Lab

6. Below, youll see your new private key. Save this key, you will use it later.

Figure 9 Saving the private key Note: In the next tasks youll be asked to use this private key. Keep it handy since youll have to use it for the rest of this lab.

Task 2 Working with the Bing Map Control In this task youll use the Bing Map Silverlight control for Windows Phone. The Bing Map Silverlight Control combines the power of Silverlight and Bing Maps to provide an enhanced mapping experience. Developers can use the Bing Maps Silverlight Control to incorporate the latest location and local search features into their applications. Youll use an existing starter solution for Microsoft Visual Studio 2010 Express for Windows Phone or Microsoft Visual Studio 2010. This solution contains a partial Windows Phone application, with startup code and UI behavior for completing this lab. 1. Open Microsoft Visual Studio 2010 Express for Windows Phone from Start | All Programs | Microsoft Visual Studio 2010 Express | Microsoft Visual Studio 2010 Express for Windows Phone. 2. In the File menu, choose Open Project. Visual Studio 2010: In the File menu, point to open and then select Project/Solution.

Page | 10

Push Notifications Hands-on Lab

3. Navigate to the starter project location at the Source\Ex1-TheBingMapControl\Begin folder of this lab, select Begin.sln and click Open.

Figure 10 Opening starter project

4. Examine the project youve just opened. This is a standard Windows Phone application consists of single page: MainPage: MainPage.xaml defines the Bing maps lab UI using XAML; youll place UI controls into this file during the lab MainPage.cs this is a partial class that contains startup code for implementing the Bing maps lab; do not change this file during the lab MainPage.xaml.cs contains the map lab logic; youll place map application logic in this file during the lab o o Resources such as icons and styles are located in the Resources folder Helper classes are placed in the Helpers folder

Page | 11

Push Notifications Hands-on Lab

5. To run the startup application, press F5. You should see the following:

Figure 11 Running the starter application

Page | 12

Push Notifications Hands-on Lab

6. During the following steps you will use the Bing map control and learn how to use it. To begin, add a reference to the Microsoft.Phone.Controls.Maps assembly.

Figure 12 Add reference to map controls assembly

Page | 13

Push Notifications Hands-on Lab

7. Open the MainPage.xaml in design mode and drag the Map control, located on the toolbox, to the center of the page. This will both add an XAML namespace and create an instance of the Bing map control for Windows Phone.

Figure 13 Map control design time

8. Open MainPage.xaml with the XAML editor, you should find something like this: XAML
<!-- Map View --> <Border x:Name="MapView" Background="Black" Height="768" Width="480"> <my:Map Name="map1" Height=50 Width=50 />

Page | 14

Push Notifications Hands-on Lab

</Border>

9. Change the map name to Map and remove both Height and Width properties so the map will stretch across the entire screen. XAML
<my:Map x:Name="Map" />

10. Press F5 to examine the map.

Figure 14 Bing map control Page | 15

Push Notifications Hands-on Lab

Note: The first time you zoom in by double clicking the map, the following message appears: Invalid Credentials. Sign up for a developer account. To remove this message, you should use the Bing Maps private key created earlier with the map.

11. Open the App.xaml.cs file and add a new internal constant string field called Id to the App class. This field will hold the Bing Maps private key youve created. You will reference this key during the lab to create credentials for both the Bing map control and Bing services. (Code Snippet Using Bing Maps Ex 1 Task 2 Step 11 Id Const) C#
internal const string Id = "your Bing maps private key";

12. Open the MainPage.xaml.cs file and add the following using statements above the class declaration. (Code Snippet Using Bing Maps Ex 1 Task 2 Step 12 Using statements) C#
using System; using System.Device.Location; using Microsoft.Phone.Controls.Maps;

13. Now that we have the private key, we want to bind the map control with that key. To do so: Locate the Fields region inside the MainPage class Create a new private read-only field of type Microsoft.Phone.Controls.Maps.CredentialsProvider Initialize it with a new instance using the private key youve just added to the App class

(Code Snippet Using Bing Maps Ex 1 Task 2 Step 13 CredentialsProvider Field) C#


private readonly CredentialsProvider _credentialsProvider = new ApplicationIdCredentialsProvider(App.Id);

Note: If the using statement for the Microsoft.Phone.Controls.Maps were not added, you should resolve this issue by either using a full qualified class name or adding the required using statement. Several code snippets in this lab assume you are aware of how to resolve this kind of inconveniences. Page | 16

Push Notifications Hands-on Lab

14. Locate the Properties region inside the MainPage class and expose the field youve just created as a public property called CredentialsProvider so you can bind it with the map control. (Code Snippet Using Bing Maps Ex 1 Task 2 Step 14 CredentialsProvider Property) C#
public CredentialsProvider CredentialsProvider { get { return _credentialsProvider; } }

15. Open the MainPage.xaml file in XAML editor, and bind the Map.CredentialsProvider property with the public property youve just created. XAML
<my:Map Name="Map" CredentialsProvider="{Binding CredentialsProvider}" />

Note: The MainPage.DataContext is set with the MainPage instance itself in the MainPage.cs file, so the implicit binding source is the MainPage instance itself.

16. Press F5 again to test the application. Zooming in, you should notice that the message that appeared previously has gone. 17. Open the MainPage.xaml file in XAML mode, and set the Map.Mode property to AerialMode with labels. This will change the map mode to be displayed in aerial view rather than road view, which is the default. XAML
<my:Map Name="Map" CredentialsProvider="{Binding CredentialsProvider}"> <my:Map.Mode> <my:AerialMode ShouldDisplayLabels="True" /> </my:Map.Mode> </my:Map>

18. Weve added a button to the application bar for changing the map mode. This buttons click event is handled by calling the ChangeMapMode method located in the Tasks region. In the MainPage.xaml.cs, locate the Tasks region inside the MainPage class. Youll find the ChangeMapMode method over there. Place code for switching from Page | 17

Push Notifications Hands-on Lab

Road to Aerial mode and vice versa, by setting the Map.Mode property with a new instance of type Microsoft.Phone.Controls.Maps.AerialMode or Microsoft.Phone.Controls.Maps.RoadMode. (Code Snippet Using Bing Maps Ex 1 Task 2 Step 18 ChangeMapMode) C#
private void ChangeMapMode() { if (Map.Mode is AerialMode) { Map.Mode = new RoadMode(); } else { Map.Mode = new AerialMode(true); } }

Page | 18

Push Notifications Hands-on Lab

19. Press F5 to test the results. For switching views, click on the eye button on the application bar. This invokes the ChangeMapMode method.

Figure 15 Aerial map mode

Page | 19

Push Notifications Hands-on Lab

Figure 16 Road map mode Note: The Silverlight Map control for Windows Phone is designed to support the data binding model. Changing properties of the Map control using data binding is a good way for handling data objects within data templates and is a best practice for decoupling the Map control from the logic behind, especially when using the MVVM (model view viewmodel) pattern. For the simplicity of this lab, we are not using a data template for the map view itself; hence the logic is located directly in the MainView code behind. From now on, we will leverage the map control data binding capabilities, although properties of the map control can be altered directly from code behind. Page | 20

Push Notifications Hands-on Lab

20. To remove the Bing logo and Copyright from the bottom, you can set both Map.CopyrightVisibility and Map.LogoVisibility to Visibility.Collapsed. XAML
<my:Map Name="Map" CredentialsProvider="{Binding CredentialsProvider}" CopyrightVisibility="Collapsed" LogoVisibility="Collapsed"> <my:Map.Mode> <my:AerialMode ShouldDisplayLabels="True" /> </my:Map.Mode> </my:Map>

You may notice that you can zoom in by double-clicking on the map. This option is implemented internally by the map control. You have an option to display the built-in zoom bar, by setting the Map.ZoomBarVisibility to Visible, but you cant change the buttons style or location. Next you will add custom zoom buttons so you can freely zoom in and out. 21. In the MainPage.xaml.cs, add a new private field of type double. (Code Snippet Using Bing Maps Ex 1 Task 2 Step 21 Zoom Field) C#
private double _zoom;

22. Find the Consts region and add three additional constant double fields to constraint the zoom level: DefaultZoomLevel = 18.0 MaxZoomLevel = 21.0 MinZoomLevel = 1.0.

(Code Snippet Using Bing Maps Ex 1 Task 2 Step 22 Zoom Level Consts) C#
private const double DefaultZoomLevel = 18.0; private const double MaxZoomLevel = 21.0; private const double MinZoomLevel = 1.0;

Page | 21

Push Notifications Hands-on Lab

23. In MainPage.xaml.cs, find the automatic property called Zoom, and change it to get or set the value of the _zoom field. In the setter, consider the zoom level constraints youve added and notify on property changed. (Code Snippet Using Bing Maps Ex 1 Task 2 Step 23 Zoom Property) C#
public double Zoom { get { return _zoom; } set { var coercedZoom = Math.Max(MinZoomLevel, Math.Min(MaxZoomLevel, value)); if (_zoom != coercedZoom) { _zoom = value; NotifyPropertyChanged("Zoom"); } } }

24. Open the MainPage.xaml in XAML editor and bind the Map.ZoomLevel property with the Zoom property youve just changed. The binding mode must be two-way. XAML
<my:Map Name="Map" LogoVisibility="Collapsed" ZoomLevel="{Binding Zoom, Mode=TwoWay}"> <my:Map.Mode> <my:AerialMode ShouldDisplayLabels="True" /> </my:Map.Mode> </my:Map>

25. Drop two buttons vertically from the toolbox into the middle left side of the map control, one for zoom-in and the other for zoom-out. XAML
<my:Map Name="Map" LogoVisibility="Collapsed" ZoomLevel="{Binding Zoom, Mode=TwoWay}"> <my:Map.Mode> <my:AerialMode ShouldDisplayLabels="True" />

Page | 22

Push Notifications Hands-on Lab

</my:Map.Mode> <Button x:Name="ButtonZoomIn" HorizontalAlignment="Left" VerticalAlignment="Top" Height="56" Width="56" Margin="8,180,0,0" /> <Button x:Name="ButtonZoomOut" HorizontalAlignment="Left" VerticalAlignment="Top" Height="56" Width="56" Margin="8,260,0,0" /> </my:Map>

26. Register the respective button Click event with the ButtonZoomIn_Click and ButtonZoomOut_Click event handlers. These event handlers are already provided in the MainView.cs file. When invoked, the ButtonZoomIn_Click event handler increases the Zoom property by one and the ButtonZoomOut_Click event handler decreases the Zoom property by one. XAML
<Button x:Name="ButtonZoomIn" HorizontalAlignment="Left" VerticalAlignment="Top" Height="56" Width="56" Margin="8,180,0,0" Click="ButtonZoomIn_Click" /> <Button x:Name="ButtonZoomOut" HorizontalAlignment="Left" VerticalAlignment="Top" Height="56" Width="56" Margin="8,260,0,0" Click="ButtonZoomOut_Click" />

27. To change the look and feel of the zoom-in and zoom-out buttons, open the MainView.xaml in XAML mode and set each Button.Style property with the appropriate ButtonZoomInStyle or ButtonZoomOutStyle style. These styles were provided with the starter solution and are located in the DefaultStyle.xaml resource file. XAML
<Button x:Name="ButtonZoomIn" Style="{StaticResource ButtonZoomInStyle}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="56" Width="56" Margin="8,180,0,0" Click="ButtonZoomIn_Click" /> <Button x:Name="ButtonZoomOut" Style="{StaticResource ButtonZoomOutStyle}" HorizontalAlignment="Left" VerticalAlignment="Top"

Page | 23

Push Notifications Hands-on Lab

Height="56" Width="56" Margin="8,260,0,0" Click="ButtonZoomOut_Click" />

28. To test the results, press F5 and click the zoom-in and zoom-out buttons.

Figure 17 Zoom out

Page | 24

Push Notifications Hands-on Lab

Figure 18 Zoom in

In the next step youll center the map to your geographic location. Since this lab works with the emulator, you dont have a real GPS device. So youll have to pre-define your geographic location using latitude and longitude coordinates. Note: You can determine your geographic location by browsing to http://www.bing.com/maps, set your location, and then copy the Latitude and Longitude coordinates from the address bar. Page | 25

Push Notifications Hands-on Lab

29. Add a reference to the System.Device assembly.

Figure 19 Reference System.Device

30. In the MainPage.xaml.cs, add a new static, read-only field of type System.Device.Location.GeoCoordinate, called DefaultLocation, and set it with a new instance using your latitude and longitude coordinates. This will be your current location. (Code Snippet Using Bing Maps Ex 1 Task 2 Step 30 DefaultLocation Field) C#
private static readonly GeoCoordinate DefaultLocation = new GeoCoordinate(47.639631, -122.127713);

31. In the MainPage.xaml.cs, add a new field of type System.Device.Location.GeoCoordinate, called _center. (Code Snippet Using Bing Maps Ex 1 Task 2 Step 31 Center Field) C#
private GeoCoordinate _center;

Page | 26

Push Notifications Hands-on Lab

32. Create a property called Center that exposes the _center field. In the setter, call the notification change method. (Code Snippet Using Bing Maps Ex 1 Task 2 Step 32 Center Property) C#
public GeoCoordinate Center { get { return _center; } set { if (_center != value) { _center = value; NotifyPropertyChanged("Center"); } } }

33. In the MainPage.xaml, bind the Map.Center property with the Center property youve created. The binding mode must be two-way. XAML
<my:Map Name="Map" CredentialsProvider="{Binding CredentialsProvider}" ZoomLevel="{Binding Zoom, Mode=TwoWay}" Center="{Binding Center, Mode=TwoWay}" > ... </my:Map>

34. In the MainPage.xaml.cs, find the CenterLocation method. The first applications bar left button event handler calls this method. Change both Center and Zoom to defaults. (Code Snippet Using Bing Maps Ex 1 Task 2 Step 34 CenterLocation Method) C#
private void CenterLocation() { Center = DefaultLocation; Zoom = DefaultZoomLevel; }

Page | 27

Push Notifications Hands-on Lab

35. To test the application, press F5 and click the application bars target icon on the left. This should zoom and center the map to the location provided by the DefaultLocation field.

Figure 20 Center and zoom map to default location

This concludes the exercise. Note: The complete solution for this exercise is provided at the following location: Source\Ex1-TheBingMapControl\End. Page | 28

Push Notifications Hands-on Lab

Page | 29

Push Notifications Hands-on Lab

Exercise 2: Handling and Customizing Pushpins


In this exercise you will: Learn how to use map layers with data binding Create a pushpin layer Add a pushpin for indicating current location Handle pushpin clicks Add pushpins from a catalog to the map Customize the pushpin look and feel

You will use the Microsoft Visual Studio 2010 Express for Windows Phone development environment, and will deploy to the Windows Phone Emulator for debugging. The solution we will be working with is based upon the previous exercise. Task 1 Creating a Pushpins Layer In this task you will learn how to create a map layer and how to populate it with pushpin data using data binding. A map layer is represented by a custom panel of type Microsoft.Phone.Controls.Maps.MapLayer. Using the MapLayer panel you can have any kind of UIElement on top of the map. The MapLayer panel knows how to lay out elements on the map using geo coordinates. A map control can have zero or more layers. Although we can add and remove visual items directly to the MapLayer panel from code behind, we will populate map layers using the data binding mechanism. Instead of using MapLayer directly, we will use another control of type Microsoft.Phone.Controls.Maps.MapItemsControl. This custom ItemsControl uses the MapLayer panel to layout items by default. 1. Open the starter solution located in the Source\Ex2-HandlingPushpins\Begin folder. Note: You should set the Bing Maps application Id in the App class with your private key created in the previous exercise.

2. To add a new pushpins layer to the map, open the MainPage.xaml in XAML editor and add a new MapItemsControl element as a child of the map control, just before the zoom buttons so the buttons will render on top. This will be our pushpins layer. XAML
<my:Map Name="Map" CredentialsProvider="{Binding CredentialsProvider}" ZoomLevel="{Binding Zoom, Mode=TwoWay}"

Page | 30

Push Notifications Hands-on Lab

Center="{Binding Center, Mode=TwoWay}"> <my:Map.Mode> <my:AerialMode ShouldDisplayLabels="True" /> </my:Map.Mode> <my:MapItemsControl /> <Button x:Name="ButtonZoomIn" Style="{StaticResource ButtonZoomInStyle}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="56" Width="56" Margin="8,180,0,0" Click="ButtonZoomIn_Click" /> <Button x:Name="ButtonZoomOut" Style="{StaticResource ButtonZoomOutStyle}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="56" Width="56" Margin="8,260,0,0" Click="ButtonZoomOut_Click" /> </my:Map>

3. To populate the new pushpins layer with pushpins data, create a new project folder called Models. 4. Under the Models folder, create a new public class called PushpinModel. This class represents the pushpin data.

Figure 21 Pushpin model Page | 31

Push Notifications Hands-on Lab

5. Add a new automatic public property called Location of type System.Device.Location.GeoCoordinate to the PushpinModel. This property indicates the pushpins geographical location on the map. (Code Snippet Using Bing Maps Ex 2 Task 1 Step 5 Location Property) C#
public class PushpinModel { public GeoCoordinate Location { get; set; } }

6. To populate the pushpins layer with pushpins, add a new private read-only field called _pushpins of type ObservableCollection<PushpinModel> to MainPage.xaml.cs, and initialize it with one PushpinModel instance using the default location. (Code Snippet Using Bing Maps Ex 2 Task 1 Step 6 Pushpins Field) C#
private readonly ObservableCollection<PushpinModel> _pushpins = new ObservableCollection<PushpinModel> { new PushpinModel { Location = DefaultLocation } };

7. Expose the _pushpins field with public property so you can bind it with the pushpins layer. (Code Snippet Using Bing Maps Ex 2 Task 1 Step 7 Pushpins Property) C#
public ObservableCollection<PushpinModel> Pushpins { get { return _pushpins; } }

8. Open the MainPage.xaml in XAML editor and bind the MapItemsControl youve added with the Pushpins collection. XAML Page | 32

Push Notifications Hands-on Lab

<my:MapItemsControl ItemsSource="{Binding Pushpins}" />

9. If you run the application, youll notice that the pushpin data is added to the maps top left corner as a text block. You can change that by simply creating a data template. To create a data template, set the MapItemsControl.ItemTemplate property with a DataTemplate element that contains one Pushpin. XAML
<my:MapItemsControl ItemsSource="{Binding Pushpins}"> <my:MapItemsControl.ItemTemplate> <DataTemplate> <my:Pushpin /> </DataTemplate> </my:MapItemsControl.ItemTemplate> </my:MapItemsControl>

10. In order to place the pushpin at the exact location on the map, bind the Pushpin.Location property with the Location property of the PushpinModel. XAML
<my:MapItemsControl ItemsSource="{Binding Pushpins}"> <my:MapItemsControl.ItemTemplate> <DataTemplate> <my:Pushpin Location="{Binding Location}" /> </DataTemplate> </my:MapItemsControl.ItemTemplate> </my:MapItemsControl>

11. Set the Pushpin.Content property to My Location. XAML


<my:Pushpin Location="{Binding Location}" Content="My Location" />

Page | 33

Push Notifications Hands-on Lab

12. Press F5 to test the results. You should see a black pushpin with a text label. This is the pushpin youve just added with a default black style. If you click on the current location icon on the application bar, the map will center on the default location and youll see the pushpin in the center.

Figure 22 Pushpin default style

13. A pushpin can be customized easily. It is a ContentControl; hence we can change its style and control template. To create a new pushpin style and control template, open Page | 34

Push Notifications Hands-on Lab

the DefaultStyle.xaml resource dictionary located in the Resources/Styles project folder and map the Bing maps control namespace. XAML
<ResourceDictionary ... xmlns:m="clrnamespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Control s.Maps"> <!-- Next step, pushpin style comes here --> </ResourceDictionary>

14. Inside the DefaultStyle.xaml resource dictionary, create a new style for the pushpin as follows: XAML
<Style x:Key="PushpinStyle" TargetType="m:Pushpin"> <Setter Property="BorderBrush" Value="#FFF4F4F5" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Canvas Height="0" RenderTransformOrigin="0.5,0.5" Width="0"> <Canvas RenderTransformOrigin="0.5,0.5" Height="1" Width="1"> <Path Data="M22.5,1 C34.374123,1 44,10.625878 44,22.5 C44,31.034525 39.027256,38.407604 31.821138,41.879868 L31.359026,42.095631 L22.702744,60.864998 L13.900847,42.209641 L13.651964,42.100761 C6.1912994,38.727623 0.99999976,31.220058 1,22.5 C0.99999976,10.625878 10.625878,1 22.5,1 z" Fill="{TemplateBinding BorderBrush}" Height="61.865" Stretch="Fill" Stroke="Black" StrokeThickness="2" StrokeLineJoin="Miter" UseLayoutRounding="False" Width="45" RenderTransformOrigin="0.5,0.5" Canvas.Left="-2.703" Canvas.Top="-7.187" > <Path.RenderTransform> <CompositeTransform TranslateX="-20"

Page | 35

Push Notifications Hands-on Lab

TranslateY="-55"/> </Path.RenderTransform> </Path> <Path Data="M35,17.5 C35,27.164984 27.164984,35 17.5,35 C7.8350167,35 0,27.164984 0,17.5 C0,7.8350167 7.8350167,0 17.5,0 C27.164984,0 35,7.8350167 35,17.5 z" Fill="{TemplateBinding Background}" HorizontalAlignment="Left" Height="35" Stretch="Fill" StrokeThickness="2" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5" Width="35" UseLayoutRounding="False" Canvas.Top="-7.4" Canvas.Left="-2.888" > <Path.RenderTransform> <CompositeTransform TranslateX="-15" TranslateY="-50"/> </Path.RenderTransform> </Path> </Canvas> <ContentPresenter Width="35" Height="35" RenderTransformOrigin="0.5,0.5" Canvas.Top="-3.5"> <ContentPresenter.RenderTransform> <CompositeTransform TranslateX="-18" TranslateY="-54"/> </ContentPresenter.RenderTransform> </ContentPresenter> </Canvas> </ControlTemplate> </Setter.Value> </Setter> </Style>

Note: If you design your own pushpin control template, you should know that the default relative point of a pushpin when scaling the map (zoom) is the bottom left corner, not the center or top left. You can easily create your own control template using Microsoft Expression Blend for Windows Phone, which is part of the Windows Phone development tools.

15. Add new public property of type Uri, named Icon to the PushpinModel. You will use it to bind the image of the pushpin. Page | 36

Push Notifications Hands-on Lab

(Code Snippet Using Bing Maps Ex 2 Task 1 Step 15 Icon Property) C#


public class PushpinModel { public GeoCoordinate Location { get; set; } public Uri Icon { get; set; } }

16. Under the Resources\Icons folder, create a new folder called Pushpins, and add all images from the Source\Assets\Resources\Pushpins folder.

Figure 23 Pushpin images

Page | 37

Push Notifications Hands-on Lab

17. Change each of the images build actions from Resource to Content. To do so, select all pushpin images, right click, select properties, and change the Build Action to Content.

Figure 24 Changing pushpin images build action to Content

18. In the MainPage.xaml, set the style of the pushpin to the one youve added. XAML
<my:MapItemsControl ItemsSource="{Binding Pushpins}"> <my:MapItemsControl.ItemTemplate> <DataTemplate> <my:Pushpin Style="{StaticResource PushpinStyle}" Location="{Binding Location}" /> </DataTemplate> </my:MapItemsControl.ItemTemplate> </my:MapItemsControl>

19. Set the content of the pushpin to an Image element and bind the Image.Source property to the PushpinModel.Icon property. XAML
<my:MapItemsControl ItemsSource="{Binding Pushpins}"> <my:MapItemsControl.ItemTemplate> <DataTemplate> <my:Pushpin Style="{StaticResource PushpinStyle}" Location="{Binding Location}"> <Image Source="{Binding Icon}" /> </my:Pushpin> </DataTemplate> </my:MapItemsControl.ItemTemplate>

Page | 38

Push Notifications Hands-on Lab

</my:MapItemsControl>

20. In the MainPage.xaml.cs, set the PushpinData.Icon property of pushpin instance youve created before with a relative Uri to the PushpinLocation.png icon file located in the Pushpins project folder. (Code Snippet Using Bing Maps Ex 2 Task 1 Step 20 Pushpin Icon Value) C#
private readonly ObservableCollection<PushpinModel> _pushpins = new ObservableCollection<PushpinModel> { new PushpinModel { Location = DefaultLocation, Icon = new Uri("/Resources/Icons/Pushpins/PushpinLocation.png", UriKind.Relative) } };

Page | 39

Push Notifications Hands-on Lab

21. Press F5 to see the results. You should observe that the pushpins default black style has changed, and now it looks like the pushpin in Bing maps over the web.

Figure 25 Custom pushpin style

Task 2 Creating a Pushpins Catalog In this task youll create a pushpin catalog and display it using a popup window. To build a catalog, you will bind a list box to a collection of predefined pushpin models. Selecting a pushpin Page | 40

Push Notifications Hands-on Lab

from the catalog will clone it and add that pushpin to the touched area. You will use the Map control APIs to translate a view point to geographic location. 1. Add a new public property of type string, named TypeName to the PushpinModel class youve created, located in the Models project folder. Youll use this type name to pick a different color for different types of pushpins. (Code Snippet Using Bing Maps Ex 2 Task 2 Step 1 TypeName Property) C#
public class PushpinModel { public GeoCoordinate Location { get; set; } public Uri Icon { get; set; } public string TypeName { get; set; } }

2. Add the PushpinCatalog.cs C# file located in the Source\Assets\Code folder to the Models project folder. This file defines a class which contains one pushpin instance per pushpin type. C#
public class PushpinCatalog { private List<PushpinModel> _items; public IEnumerable<PushpinModel> Items { get { return _items; } } public PushpinCatalog() { InitializePuspins(); } private void InitializePuspins() { string[] pushpinIcons = { "PushpinBicycle.png", "PushpinCar.png", "PushpinDrink.png", "PushpinFuel.png", "PushpinHouse.png",

Page | 41

Push Notifications Hands-on Lab

"PushpinRestaurant.png", "PushpinShop.png" }; var pushpins = from icon in pushpinIcons select new PushpinModel { Icon = new Uri("/Resources/Icons/Pushpins/" + icon, UriKind.Relative), TypeName = System.IO.Path.GetFileNameWithoutExtension(icon) }; _items = pushpins.ToList(); } }

3. In the MainPage.xaml, find the PushpinPopup popup element and add a ListBox named ListBoxPushpinCatalog as its only child. XAML
<Popup x:Name="PushpinPopup" IsOpen="False" Canvas.Top="330" Canvas.Left="25" Opacity="0"> <ListBox x:Name="ListBoxPushpinCatalog" /> </Popup>

4. Set the following ListBox properties: XAML


<ListBox x:Name="ListBoxPushpinCatalog" Width="392" Height="56" Background="{StaticResource ControlBackgroundBrush}"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal" /> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox>

5. To create an instance of the catalog and bind the list box with the catalogs items, map the UsingBingMaps.Models CLR namespace using xmlns. XAML
<phone:PhoneApplicationPage x:Class="UsingBingMaps.MainPage"

Page | 42

Push Notifications Hands-on Lab

... xmlns:models="clr-namespace:UsingBingMaps.Models"> ... </phone:PhoneApplicationPage>

6. Set the ListBox.DataContext property with a fresh instance of type PushpinCatalog and bind the list box with the PushpinCatalog.Items. XAML
<ListBox x:Name="ListBoxPushpinCatalog" Width="392" Height="56" Background="{StaticResource ControlBackgroundBrush}" ItemsSource="{Binding Items}"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal" /> </ItemsPanelTemplate> </ListBox.ItemsPanel> <ListBox.DataContext> <models:PushpinCatalog /> </ListBox.DataContext> </ListBox>

7. Create a list box item template which has a single instance of type Image. Bind the Image.Source to the PushpinModel.Icon property, and set the image size to 56x56. XAML
<ListBox.ItemTemplate> <DataTemplate> <Image Width="56" Height="56" Source="{Binding Icon}" /> </DataTemplate> </ListBox.ItemTemplate>

8. To center the popup at the exact touch location, find the CenterPushpinsPopup method located in the MainPage.xaml.cs file, and add logic to calculate the popups Canvas.Top value based on the size of the list box and the touch point. (Code Snippet Using Bing Maps Ex 2 Task 2 Step 8 Canvas SetTop) C#
private void CenterPushpinsPopup(Point touchPoint) { Canvas.SetTop(PushpinPopup, touchPoint.Y ListBoxPushpinCatalog.Height / 2);

Page | 43

Push Notifications Hands-on Lab

9. To see the results, press F5. When the map loaded, press and hold the left mouse button on the map. This should open the popup. This behavior already exists as part of the starter solution.

Figure 26 Pushpin catalog

Page | 44

Push Notifications Hands-on Lab

10. Now that the catalog is ready, lets add logic to pick a pushpin and place it at the exact location. Register the ListBox.SelectionChanged event with the ListBoxPushpinCatalog_SelectionChanged event handler provided with the starter solution. 11. Add a new method named Clone to the PushpinModel class. This method should return a clone of the PushpinModel instance with a different geo location provided as parameter of type GeoCoordinate. (Code Snippet Using Bing Maps Ex 2 Task 2 Step 11 Clone Method) C#
public PushpinModel Clone(GeoCoordinate location) { return new PushpinModel { Location = location, TypeName = TypeName, Icon = Icon }; }

12. In the MainPage.xaml.cs, find the CreateNewPushpin method. This method is called by the ListBoxPushpinCatalog_SelectionChanged located in the MainPage.cs. It has two parameters: the selected pushpin model and the exact touch point in view coordinates. Translate the touch point to geo coordinates using the Map.TryViewportPointToLocation method. (Code Snippet Using Bing Maps Ex 2 Task 2 Step 12 Translate Location) C#
private void CreateNewPushpin(object selectedItem, Point point) { GeoCoordinate location; Map.TryViewportPointToLocation(point, out location); }

13. Now that youve got the exact geo coordinate for the pushpin, clone the selected pushpin with the new coordinate, and add the clone to the Pushpins collection. This will generate a new pushpin on the correct geo location on the map. (Code Snippet Using Bing Maps Ex 2 Task 2 Step 13 Add Pushpin Clone) C#
private void CreateNewPushpin(object selectedItem, Point point)

Page | 45

Push Notifications Hands-on Lab

{ GeoCoordinate location; Map.TryViewportPointToLocation(point, out location); var pushpinPrototype = selectedItem as PushpinModel; var pushpin = pushpinPrototype.Clone(location); Pushpins.Add(pushpin); }

14. To change the pushpin colors, add the following brushes to the DefaultStyle.xaml located in the Resources\Styles project folder. XAML
<!-- # Brushes --> <SolidColorBrush x:Key="PushpinBicycleBrush" Color="#FF593D00" /> <SolidColorBrush x:Key="PushpinCarBrush" Color="#FFEC098D" /> <SolidColorBrush x:Key="PushpinDrinkBrush" Color="#FFD21242" /> <SolidColorBrush x:Key="PushpinFuelBrush" Color="#FFF47836" /> <SolidColorBrush x:Key="PushpinHouseBrush" Color="#FF00AFDB" /> <SolidColorBrush x:Key="PushpinLocationBrush" Color="#FF3784DF" /> <SolidColorBrush x:Key="PushpinRestaurantBrush" Color="#FF7D4199" /> <SolidColorBrush x:Key="PushpinShopBrush" Color="#FF00B25A" />

15. Add a new project folder called Converters, and within it create a new value converter class that converts the pushpin TypeName to the exact brush, and add it as a resource to the DefaultStyles.xaml resource dictionary. (Code Snippet Using Bing Maps Ex 2 Task 2 Step 15 PushpinTypeBrushConverter Class) C#
public class PushpinTypeBrushConverter : IValueConverter

Page | 46

Push Notifications Hands-on Lab

{ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { var brushKey = string.Format("{0}Brush", value); var brush = Application.Current.Resources[brushKey] ?? DefaultBrush; return brush; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotSupportedException(); } static PushpinTypeBrushConverter() { DefaultBrush = new SolidColorBrush(Color.FromArgb(0xFF, 0x37, 0x84, 0xDF)); } public static Brush DefaultBrush; }

XAML
<ResourceDictionary ... xmlns:converters="clr-namespace:UsingBingMaps.Converters"> <converters:PushpinTypeBrushConverter x:Key="PushpinTypeBrushConverter" /> </ResourceDictionary>

16. In the MainPage.xaml, search for the Map control. In the pushpin data template, use the converter instance you created to bind the Pushpin.Background property to the PushpinModel.TypeName property. XAML
<my:MapItemsControl ItemsSource="{Binding Pushpins}"> <my:MapItemsControl.ItemTemplate> <DataTemplate> <my:Pushpin Style="{StaticResource PushpinStyle}" Location="{Binding Location}"

Page | 47

Push Notifications Hands-on Lab

Background="{Binding TypeName, Converter={StaticResource PushpinTypeBrushConverter}}"> <Image Source="{Binding Icon}" /> </my:Pushpin> </DataTemplate> </my:MapItemsControl.ItemTemplate> </my:MapItemsControl>

17. To center the map on a pushpin while touching it, register the Pushpin.MouseLeftButtonUp event. Since the Pushpin is defined by a DataTemplate located directly inside MainPage.xaml, you can simply register the event handler over there. Otherwise you can use an Attached Behavior to activate a command. In the pushpin DataTemplate, register to the Pushpin.MouseLeftButtonUp event and handle it by setting the MainPage.Center property with the pushpins Location property. You can extract the pushpin object from the event handler sender argument. XAML
<my:Pushpin Style="{StaticResource PushpinStyle}" MouseLeftButtonUp="Pushpin_MouseLeftButtonUp" Location="{Binding Location}" Background="{Binding TypeName, Converter={StaticResource PushpinTypeBrushConverter}}"> <Image Source="{Binding Icon}" /> </my:Pushpin>

(Code Snippet Using Bing Maps Ex 2 Task 2 Step 17 Pushpin_MouseLeftButtonUp Event Handler) C#
private void Pushpin_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { var pushpin = sender as Pushpin; Center = pushpin.Location; }

Page | 48

Push Notifications Hands-on Lab

18. To test the results, press F5, go to the default location, click and hold a position on the map then select a pushpin from the list. The pushpin youve selected should be added to the map. Repeat this behavior for adding more pushpins. Click on any pushpin to center the map on it.

Figure 27 Pushpin selection This concludes the exercise. Note: The complete solution for this exercise is provided at the following location: Source\Ex2-HandlingPushpins\End. Page | 49

Push Notifications Hands-on Lab

Exercise 3: Calculating a Route


In this exercise we will: Create a map route layer Use Bing services to calculate to and from routes Display calculated route itineraries

We will use the Microsoft Visual Studio 2010 Express for Windows Phone development environment, and will deploy to the Windows Phone Emulator for debugging. The solution we will be working with is based upon the previous exercise.

Task 1 Adding a Route to the Map In this task youll work with Bing Maps SOAP services to calculate a route from point A to point B, and then youll create a route layer for rendering the calculated route. As part of the route rendering, youll also render route itineraries provided by the Bing Maps services. In this task youll use the following services: Geocode Service to match addresses, places, and geographic entities to latitude and longitude coordinates on the map, as well as return location information for a specified latitude and longitude coordinate Route Service to generate routes and driving directions based on locations or waypoints, for example, directions that include traffic warnings and route hints between multiple locations, and directions from all major roads to a destination (1-click directions, also referred to as a "party map") Search Service to parse a search query that contains a location or keyword (or both) and return search result

1. Open the starter solution located in the Source\Ex3-RouteCalculation\Begin folder. Note: You should set the Bing Maps application Id in the App class with your private key created in the previous exercise.

Page | 50

Push Notifications Hands-on Lab

2. To add a reference to the Bing Maps Geocode service, right click on the project references, and select Add Service Reference.

Figure 28 Add Service Reference

3. Paste the following service address into the opened dialog, and click Go: http://dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc

Page | 51

Push Notifications Hands-on Lab

4. In the Namespace field, make sure that you enter Bing.Geocode and then click OK.

Figure 29 Bing Service

Note: If you have problems generating the data from the service, please make sure that you are currently connected to the Internet. Try to paste the service address into the web browser;, you should get a service test page. If you have a connection, try to run Visual Studio 2010 again as Administrator (right click on Visual Studio 2010 icon on start menu, select Run as administrator), then try again.

5. To add reference to the Bing Maps Route service, right-click the project references, and select Add Service Reference 6. Paste the following service address into the opened dialog, and click Go: http://dev.virtualearth.net/webservices/v1/routeservice/routeservice.svc 7. In the Namespace field, make sure that you enter Bing.Route and then click OK. 8. To add a reference to the Bing Maps Search service, right-click the project references, and select Add Service Reference Page | 52

Push Notifications Hands-on Lab

9. Paste the following service address into the opened dialog, and click Go: http://dev.virtualearth.net/webservices/v1/searchservice/searchservice.svc 10. In the Namespace field, make sure that you enter Bing.Search and then click OK. 11. Open the ServiceReferences.ClientConfig configuration file that was automatically created as a project item and delete all CustomBinding related entries. In this lab we will use only the basic http bindings. You should have a file that looks like this: XAML
<configuration> <system.serviceModel> <bindings> <basicHttpBinding> <binding name="BasicHttpBinding_IGeocodeService" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"> <security mode="None" /> </binding> <binding name="BasicHttpBinding_IRouteService" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"> <security mode="None" /> </binding> <binding name="BasicHttpBinding_ISearchService" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"> <security mode="None" /> </binding> </basicHttpBinding> </bindings> <client> <endpoint address="http://dev.virtualearth.net/webservices/v1/geocodeservice/Geoco deService.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IGeocodeService" contract="Bing.Geocode.IGeocodeService" name="BasicHttpBinding_IGeocodeService" /> <endpoint address="http://dev.virtualearth.net/webservices/v1/routeservice/routese rvice.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IRouteService" contract="Bing.Route.IRouteService" name="BasicHttpBinding_IRouteService" /> <endpoint address="http://dev.virtualearth.net/webservices/v1/searchservice/search service.svc"

Page | 53

Push Notifications Hands-on Lab

binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ISearchService" contract="Bing.Search.ISearchService" name="BasicHttpBinding_ISearchService" /> </client> </system.serviceModel> </configuration>

Note: Youve now added three Bing Maps services. Next youll add a helper class that uses these services to wrap part of the asynchronous calls for calculating a route.

12. Add the following files to the Helpers project folder: RouteCalculator.cs, RoutingState.cs, RouteCalculationError.cs, located in Source/Assets/Code. These files will help you calculate a route using the Bing Maps Services youve added. The RouteCalculator class exposes one public method called CalculateAsync and one public event called Error. To calculate a route all you have to do is to initialize a new instance of the RouteCalculator type with the following parameter: Map credentials, To string, From string, UI dispatcher, and a delegate that will be called on the UI thread when calculation is done. If an error occurs, the Error event is raised on the UI thread. This is why you must pass the UI dispatcher.

Figure 30 Route Helpers

13. Add a model public class called RouteModel to the Models project folder, for representing the route data. Page | 54

Push Notifications Hands-on Lab

14. In the RouteModel class add a new collection of type Microsoft.Phone.Controls.Maps.LocationCollection to hold the route coordinates, and expose this as a public property called Locations. 15. Create a constructor with one collection parameter of type Microsoft.Phone.Controls.Maps.Platform.Location. Use it to initialize the internal collection. Location has an implicit cast to the GeoCoordinate type. (Code Snippet Using Bing Maps Ex 3 Task 1 Step 15 RouteModel Constructor) C#
public class RouteModel { private readonly LocationCollection _locations; public ICollection<GeoCoordinate> Locations { get { return _locations; } } public RouteModel(ICollection<Location> locations) { _locations = new LocationCollection(); foreach (Location location in locations) { _locations.Add(location); } } }

16. In the MainPage.xaml.cs, add a new ObservableCollection<RouteModel> and expose it with a public property called Routes. This collection holds the calculated route and will be bound with the route layer. (Code Snippet Using Bing Maps Ex 3 Task 1 Step 16 Routes Property) C#
private readonly ObservableCollection<RouteModel> _routes = new ObservableCollection<RouteModel>(); public ObservableCollection<RouteModel> Routes { get { return _routes; } }

Page | 55

Push Notifications Hands-on Lab

17. Add two public string properties: To and From. Youll use these properties for the route calculation. (Code Snippet Using Bing Maps Ex 3 Task 1 Step 17 To From Properties) C#
public string To { get; set; } public string From { get; set; }

18. Find the CalculateRoute method and calculate a route using the route calculator helper class: Create a try/catch block and use MessageBox to display an error message in case an exception is caught. (Code Snippet Using Bing Maps Ex 3 Task 1 Step 18 PushpinTypeBrushConverter Class) C#
private void CalculateRoute() { try { // TODO : Calculate a route. } catch (Exception ex) { MessageBox.Show(ex.Message); } }

19. To calculate a route asynchronously, create an instance of RouteCalculator inside the try block. So far you should have all the required parameters as properties of the MainPage class, except for the last one which will be an empty lambda expression with a single result parameter. (Code Snippet Using Bing Maps Ex 3 Task 1 Step 19 routeCalculator) C#
try { var routeCalculator = new RouteCalculator( CredentialsProvider, To, From, Dispatcher, result =>

Page | 56

Push Notifications Hands-on Lab

{ }); } catch (Exception ex) { MessageBox.Show(ex.Message); }

20. Register the RouteCalculator.Error event by displaying an error message to the user and then call the RouteCalculator.CalculateAsync method to start the route calculation. (Code Snippet Using Bing Maps Ex 3 Task 1 Step 20 Calculate) C#
try { var routeCalculator = new RouteCalculator( CredentialsProvider, To, From, Dispatcher, result => { }); // Display an error message in case of fault. routeCalculator.Error += r => MessageBox.Show(r.Reason); // Start the route calculation asynchronously. routeCalculator.CalculateAsync(); } catch (Exception ex) { MessageBox.Show(ex.Message); }

21. When the route calculation is finished, the lambda expression should be invoked. Inside the lambda expression, clear the Route collection. For the simplicity, youll have only one route at a time. (Code Snippet Using Bing Maps Ex 3 Task 1 Step 21 Clear Routes) C#
result =>

Page | 57

Push Notifications Hands-on Lab

{ Routes.Clear(); };

22. Below, create a new RouteModel instance based on route calculator parameter (result.Result.RoutePath.Points), and add the new route to the route collection. (Code Snippet Using Bing Maps Ex 3 Task 1 Step 22 routeModel) C#
var routeModel = new RouteModel(result.Result.RoutePath.Points); Routes.Add(routeModel);

23. Then, center the map on the new route, by calling Map.SetView, and passing it a LocationRect instance which is can be calculated using the LocationRect.CreateLocationRect static helper method. (Code Snippet Using Bing Maps Ex 3 Task 1 Step 23 viewRect) C#
var viewRect = LocationRect.CreateLocationRect(routeModel.Locations); Map.SetView(viewRect);

24. To pick the routes to/from text, open the MainPage.xaml with the XAML editor, find the RouteView border and add a new child composed of a Grid with two TextBlocks, one for From and the other for To. XAML
<Border x:Name="RouteView" Height="160" Margin="0" Padding="8" RenderTransformOrigin="0.5,0.5" Width="480" Background="{StaticResource ControlBackgroundBrush}"> <Border.RenderTransform> <CompositeTransform TranslateY="-160"/> </Border.RenderTransform> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="50" /> <ColumnDefinition Width="0.8*" /> <ColumnDefinition Width="0.2*"/>

Page | 58

Push Notifications Hands-on Lab

</Grid.ColumnDefinitions> <TextBlock Text="From" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" /> <TextBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" /> <TextBlock Text="To" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" /> <TextBox Grid.Row="1" Grid.Column="1" /> </Grid> </Border>

25. Bind each of the TextBlocks as two-way binding with the relevant To/From properties. XAML
<TextBox Text="{Binding From, Mode=TwoWay}" ... /> <TextBox Text="{Binding To, Mode=TwoWay}" ... />

26. Add a Go button to the Grid, set its style with the ButtonGoStyle style and register its Click event with the ButtonGo_Click event handler. Both the style and the event handler are provided with the starter project. XAML
<Button Content="Go" Grid.Column="2" Grid.Row="1" Click="ButtonGo_Click" Style="{StaticResource ButtonGoStyle}" />

27. To create a route layer, add another MapItemsControl to the map control just before the pushpins layer, and bind it to the Routes property. XAML
<my:MapItemsControl ItemsSource="{Binding Routes}" />

28. To draw the route as a single line on the map, set the MapItemsControl.ItemTemplate with a data templatethat contains a single MapPolyline instance. XAML
<my:MapItemsControl.ItemTemplate> <DataTemplate> <my:MapPolyline Stroke="#FF2C76B7" Opacity="0.85" StrokeThickness="6" />

Page | 59

Push Notifications Hands-on Lab

</DataTemplate> </my:MapItemsControl.ItemTemplate>

29. Bind the MapPolyline instance with the RouteModel.Locations property. XAML
<my:MapPolyline Stroke="#FF2C76B7" Opacity="0.85" StrokeThickness="6" Locations="{Binding Locations}" />

30. To test the application: Press F5 and then click on route icon on the application bar (the upward-facing arrow). The route view should slide down from the top. Write a valid address in the From and To fields. For example: Microsoft Redmond Building 1, WA, Microsoft Redmond Building 9, WA. Click the search icon. This should calculate the route and you should see it on the map. If an error occurs, you should see an error message.

Page | 60

Push Notifications Hands-on Lab

Figure 31 Calculating a route

Task 2 Displaying Route Itineraries The Bing route service supplies additional data with the route data, namely, the route itineraries data. By using the itineraries data you can display the exact directions of how to walk or drive from point A to point B on the route. In this task youll create a directions list based on these itineraries.

Page | 61

Push Notifications Hands-on Lab

1. In the MainPage.xaml.cs, add a new collection of type ItineraryItem, and expose it as public property called Itineraries. This type was auto generated as part of the Bing Route service data contracts. Youll use this class to encapsulate the itineraries collection provided with the route. (Code Snippet Using Bing Maps Ex 3 Task 2 Step 1 ItineraryItem Property) C#
private readonly ObservableCollection<ItineraryItem> _itineraries = new ObservableCollection<ItineraryItem>(); public ObservableCollection<ItineraryItem> Itineraries { get { return _itineraries; } }

2. Find the CalculateRoute method and clear both the Routes collection and the Itineraries collection. Since youre displaying only one route at a time youll provide the itineraries of that active route. (Code Snippet Using Bing Maps Ex 3 Task 2 Step 2 Clear Itineraries) C#
result => { Routes.Clear(); Itineraries.Clear(); ... }

3. After adding the new route to the collection of routes, add all the itineraries provided by result.Result.Legs[0] right. (Code Snippet Using Bing Maps Ex 3 Task 2 Step 3 Add Itineraries) C#
var routeModel = new RouteModel(result.Result.RoutePath.Points); Routes.Add(routeModel); foreach (var itineraryItem in result.Result.Legs[0].Itinerary) { Itineraries.Add(itineraryItem); }

Page | 62

Push Notifications Hands-on Lab

4. In the MainPage.xaml, use the MapItemsControl to add a new layer for the itineraries, right below the routed layer, and bind it with the Itineraries collection. XAML
<my:MapItemsControl ItemsSource="{Binding Itineraries}"> </my:MapItemsControl>

5. To display each Itinerary as a custom pushpin, set the MapItemsControl.ItemTemplate with a new data template that contains a single pushpin. XAML
<my:MapItemsControl ItemsSource="{Binding Itineraries}"> <my:MapItemsControl.ItemTemplate> <DataTemplate> <my:Pushpin /> </DataTemplate> </my:MapItemsControl.ItemTemplate> </my:MapItemsControl>

6. Bind the pushpin with the ItineraryItem.Location property. XAML


<my:Pushpin Location="{Binding Location}" />

7. To convert the Location property to a GeoCoordinate, create a value converter. (Code Snippet Using Bing Maps Ex 3 Task 2 Step 7 LocationGeoCoordinateConverter) C#
public class LocationGeoCoordinateConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var location = (Location)value; return (GeoCoordinate)location; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

Page | 63

Push Notifications Hands-on Lab

{ throw new NotSupportedException(); } }

8. Create an instance of the value converter inside the DefaultStyles.xaml resource dictionary located in the Resources\Styles folder. XAML
<ResourceDictionary ... xmlns:converters="clr-namespace:UsingBingMaps.Converters" mc:Ignorable="d"> <converters:LocationGeoCoordinateConverter x:Key="LocationGeoCoordinateConverter" /> ... </ResourceDictionary>

9. Use the converter inside the binding extension. XAML


<my:Pushpin Location="{Binding Location, Converter={StaticResource LocationGeoCoordinateConverter}}" />

10. Create a style for displaying the itinerary pushpin as a rounded shape and place it inside the DefaultStyle.xaml resource dictionary located in the Resources\Styles folder. XAML
<Style x:Key="MapPoint" TargetType="Ellipse"> <Setter Property="Width" Value="18"/> <Setter Property="Height" Value="18"/> <Setter Property="Fill" Value="#FF003664"/> <Setter Property="Stroke" Value="AliceBlue"/> </Style> <Style x:Key="ItineraryPushpinStyle" TargetType="m:Pushpin"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="m:Pushpin"> <Grid Height="20" Width="20"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="VisualStateGroup">

Page | 64

Push Notifications Hands-on Lab

<VisualStateGroup.Transitions> <VisualTransition GeneratedDuration="0:0:0.1"> <VisualTransition.GeneratedEasingFunction> <PowerEase EasingMode="EaseIn"/> </VisualTransition.GeneratedEasingFunction> </VisualTransition> <VisualTransition GeneratedDuration="0:0:0.1" To="Selected"> <VisualTransition.GeneratedEasingFunction> <PowerEase EasingMode="EaseIn"/> </VisualTransition.GeneratedEasingFunction> </VisualTransition> </VisualStateGroup.Transitions> <VisualState x:Name="UnSelected"/> <VisualState x:Name="Selected"> <Storyboard> <ColorAnimation Duration="0" To="White" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="ellipse" d:IsOptimized="True"/> <DoubleAnimation Duration="0" To="1.3" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransfo rm.ScaleX)" Storyboard.TargetName="ellipse" d:IsOptimized="True"/> <DoubleAnimation Duration="0" To="1.3" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransfo rm.ScaleY)" Storyboard.TargetName="ellipse" d:IsOptimized="True"/> <ColorAnimation Duration="0" To="#FFF08609" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="ellipse_Center" d:IsOptimized="True"/> <DoubleAnimation Duration="0" To="1.5" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransfo rm.ScaleX)" Storyboard.TargetName="ellipse_Center" d:IsOptimized="True"/> <DoubleAnimation Duration="0" To="1.5" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransfo

Page | 65

Push Notifications Hands-on Lab

rm.ScaleY)" Storyboard.TargetName="ellipse_Center" d:IsOptimized="True"/> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Ellipse x:Name="ellipse" Style="{StaticResource MapPoint}" Width="20" Height="20" RenderTransformOrigin="0.5,0.5" Fill="White" Stroke="#FF2C76B7" StrokeThickness="3" > <Ellipse.RenderTransform> <CompositeTransform/> </Ellipse.RenderTransform> </Ellipse> <Ellipse x:Name="ellipse_Center" Style="{StaticResource MapPoint}" Width="8" Height="8" RenderTransformOrigin="0.5,0.5" Fill="Black" Stroke="{x:Null}" StrokeThickness="2" > <Ellipse.RenderTransform> <CompositeTransform/> </Ellipse.RenderTransform> </Ellipse> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>

11. Change the pushpins style to the new style youve just created. XAML
<my:Pushpin Location="{Binding Location, Converter={StaticResource LocationGeoCoordinateConverter}}" Style="{StaticResource ItineraryPushpinStyle}" />

12. To test the results, press F5 and calculate a valid route.

Page | 66

Push Notifications Hands-on Lab

Figure 32 Route with Itineraries

13. To display a list of all itineraries related to the active route, open the MainPage.xaml and search for a border named DirectionsView. This is a place holder for the itineraries view. As a child of this border, add a ListBox control and bind it to the Itineraries collection. XAML
<ListBox ItemsSource="{Binding Itineraries}" Margin="0,10" />

14. To display the different parts of the itinerary, such as the directions text and distance, create an item template composed of a horizontal StackPanel, which contains three TextBlockone for the direction instructions, one for the distance, and one for the distance unit. XAML Page | 67

Push Notifications Hands-on Lab

<ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Margin="5,2.5"> <TextBlock FontFamily="Segoe WP" FontWeight="Light" FontSize="20" Foreground="#FF666666" /> <TextBlock Margin="4,0,0,0" FontFamily="Segoe WP" FontWeight="Light" FontSize="20" Foreground="#FF1BA1E2" /> <TextBlock Text="mi" FontFamily="Segoe WP" FontWeight="Light" FontSize="20" Foreground="#FF1BA1E2" /> </StackPanel> </DataTemplate> </ListBox.ItemTemplate>

15. Bind the first text block to the Itinerary.Text property. XAML
<TextBlock FontFamily="Segoe WP" FontWeight="Light" FontSize="20" Foreground="#FF666666" Text="{Binding Text}" />

Note: Itinerary.Text represents collection of XML elements. Each element represents a different part of the directions story, such as distance, location name, action (turn left, right, etc.). To reduce the labs complexity, youll create a value converter which converts all elements from the text property into a single line text sentence.

16. Add a new value converter called ItineraryTextConverter to the Converters project folder. Note: To implement a value converter class, inherit the class from the IValueConverter interface and implement its methods by right clicking on the interface name. By doing this you will implement the Convert and ConvertBack stub methods. Page | 68

Push Notifications Hands-on Lab

17. In the Convert method, create a StringBuilder used for building the single line text sentence. (Code Snippet Using Bing Maps Ex 3 Task 2 Step 17 textBuilder) C#
var textBuilder = new StringBuilder();

Note: Since Itinerary.Text doesnt represent a well formatted XML, and instead provides a collection of elements with no root element, and because the VirtualEarth prefix is used but is not defined, we're adding a fictitious root element that also maps the VirtualEarth prefix to a fictitious namespace.

18. Create a string variable with the following content: (Code Snippet Using Bing Maps Ex 3 Task 2 Step 18 validXmlText) C#
string validXmlText = string.Format("<Directives xmlns:VirtualEarth=\"http://BingMaps\">{0}</Directives>", value);

Note: Since we are dealing with XML and Linq, make sure you add reference to the following assemblies: System.Xml and System.Xml.Linq. Also make sure that you have a using statement for System.Linq.

19. Use XDocument to parse the XML, extract all element values, and append each to the StringBuilder. (Code Snippet Using Bing Maps Ex 3 Task 2 Step 19 Parse XML) C#
XDocument.Parse(validXmlText) .Elements() .Select(e => e.Value) .ToList() .ForEach(v => textBuilder.Append(v));

20. Return the StringBuilder results. (Code Snippet Using Bing Maps Ex 3 Task 2 Step 20 Return Results) C#
return textBuilder.ToString();

Page | 69

Push Notifications Hands-on Lab

21. In the DefaultStyles.xaml, add an instance of the converter youve created. XAML
<ResourceDictionary ... xmlns:converters="clr-namespace:UsingBingMaps.Converters" ...> <converters:ItineraryTextConverter x:Key="ItineraryTextConverter" /> ... </ResourceDictionary>

22. Go back to the Itinerary item template and use the converter with the binding markup. XAML
<TextBlock FontFamily="Segoe WP" FontWeight="Light" FontSize="20" Foreground="#FF666666" Text="{Binding Text, Converter={StaticResource ItineraryTextConverter}}" />

23. Bind the second TextBlock with the Itinerary.Summary.Distance property. XAML
<TextBlock Margin="4,0,0,0" FontFamily="Segoe WP" FontWeight="Light" FontSize="20" Foreground="#FF1BA1E2" Text="{Binding Summary.Distance}" />

24. To display the itinerary view right after a route was found, in the MainPage.xaml.cs search the HasDirections property and return true if the Itinerary collection is not empty. (Code Snippet Using Bing Maps Ex 3 Task 2 Step 24 HasDirectories Property) C#
public bool HasDirections { get { return Itineraries.Count > 0; } }

Page | 70

Push Notifications Hands-on Lab

25. In the CalculateRoute method, call the ShowDirectionsView inside the lambda body, right after setting the map view. C#
// Set the map to center on the new route. var viewRect = LocationRect.CreateLocationRect(routeModel.Locations); Map.SetView(viewRect); ShowDirectionsView();

26. To simplify testing, search for the InitializeDefaults, and set the following defaults: (Code Snippet Using Bing Maps Ex 3 Task 2 Step 26 Set Defaults) C#
private void InitializeDefaults() { Zoom = DefaultZoomLevel; Center = DefaultLocation; From = "Microsoft Redmond Building 1, WA"; To = "Microsoft Redmond Building 9, WA"; }

Page | 71

Push Notifications Hands-on Lab

27. To test the final application, press F5 and search for a valid route. The directions view should pop up automatically.

Figure 33 Bing Maps Final This concludes the exercise and the lab. Note: The complete solution for this exercise is provided at the following location: Source\Ex3-RouteCalculation\End.

Page | 72

Push Notifications Hands-on Lab

Summary
During this lab youve learned about the Bing Silverlight Map Control for Windows Phone 7 platform. Youve created a new account for accessing Bing Maps SOAP Services and created a private key for your Windows Phone Bing Maps application. Youve learned about map layers, pushpins, and route calculations. Youve created data models related to the map and bound them to different UI parts. Youve designed styles and data templates for different parts of the map and data related to the map.

Page | 73

Das könnte Ihnen auch gefallen