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.
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 won’t be able to see retrieve Bing Maps content from the web.
In this task you’ll 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.
You’ll 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.
- 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.
- Open the project located at the Source\Ex1-TheBingMapControl\Begin folder of this lab, select Begin.sln and click Open.
- Examine the project you’ve just opened. This is a standard Windows Phone application consists of single page: MainPage:
- MainPage.xaml – defines the Bing maps lab UI using XAML; you’ll 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; you’ll place map application logic in this file during the lab
- Resources such as icons and styles are located in the Resources folder
- Helper classes are placed in the Helpers folder
- 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.
- 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.
Open MainPage.xaml with the XAML editor, you should find something like this:
<!-- Map View --> <Border x:Name="MapView" Background="Black" Height="768" Width="480"> <my:Map Name="map1" Height=”50” Width=”50” /> </Border>
Change the map name to Map and remove both Height and Width properties so the map will stretch across the entire screen.
<my:Map x:Name="Map" />
Press F5 to examine the map.
Figure 6
Bing map control
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.
Stop debugging and 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 you’ve created. You will reference this key during the lab to create credentials for both the Bing map control and Bing services.
internal const string Id = "your Bing maps private key";
Open the MainPage.xaml.cs file and add the following using statements above the class declaration.
using System; using System.Device.Location; using Microsoft.Phone.Controls.Maps;
- 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 you’ve just added to the App class
private readonly CredentialsProvider _credentialsProvider = new ApplicationIdCredentialsProvider(App.Id);
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.
Locate the “Properties” region inside the MainPage class and expose the field you’ve just created as a public property called CredentialsProvider so you can bind it with the map control.
public CredentialsProvider CredentialsProvider { get { return _credentialsProvider; } }
Open the MainPage.xaml file in XAML editor, and bind the Map.CredentialsProvider property with the public property you’ve just created.
<my:Map Name="Map"
FakePre-4200c3fac1a84f3b835e94d17cdf4b2b-b64f5685d1d74ffc97f3234f0fba30b1FakePre-830fc9b8cb1942f180671e91677f3f98-58187d7857ab47cc8834c58a9085ec21FakePre-eae417e4258348969e485b01c560ba9e-9aa4b893276b45b686d847f0c11382b1FakePre-ad963eeb07b04dde9eeaa48a847c6b30-f0e1f0c8e84142888b57deda9f869e52FakePre-bda4a97f640647279213c402e161d636-d8ce6e76822043e09cc14414e94a144fFakePre-75310a3b9364456bb2f174378279186b-54281dab407146c1ab1c253487b209adFakePre-e59a6cd3337f43968d69bb7ec82b68cb-dc4e6d43d9f54a58a2a1d78fe01356a5FakePre-4f21aba0345a4d7290a1927d17208c8a-4cc5171a93c74b43ba23173dafdfd28cFakePre-7128517e493847ad8d33863ff90a65cd-b2ca2c56e2c3474386ada1693c830c6eFakePre-7efe5ccd0b0c4dbe8db3c0449eec650c-8c24dc0798e849c499908a19a46e9e8fFakePre-2440d9faa1eb4033a39a3b82281b744e-f0dcfc77a28b4b28b05bd2587d8d955fFakePre-d2af73d6b9e543f0bed665e438e0e0c9-1dc669b2013746c4bc7b9443393698d1FakePre-0556a16475254b168ec68d94a934ed4e-69335e7a28a645ec8575f6831d502d00FakePre-e59ba1bdc56040568824759d4b509982-ce502cee07924f07982b7b0d0a8977b9FakePre-70250ca9098d4c6daf3728d8cdddc229-b471652fa91d4b10b93b0e8f47242501FakePre-ecd0efbf909c4ccf9e211c0f3332cced-dbda5850c0594f3986153169898f2c62FakePre-60241f2cbf584b039c2821ebfc551374-c24ac74141ef48bbb113804f0dbd314eFakePre-4b1923a9c4e04c49bc23e1d1f55f9c72-d420dce9c3de44a7bfed61150ec130f0
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.
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.
<my:Map Name="Map" CredentialsProvider="{Binding CredentialsProvider}"> <my:Map.Mode> <my:AerialMode ShouldDisplayLabels="True" /> </my:Map.Mode> </my:Map>
We’ve added a button to the application bar for changing the map mode. This button’s 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. You’ll find the ChangeMapMode method over there. Place code for switching from 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.
private void ChangeMapMode() { if (Map.Mode is AerialMode) { Map.Mode = new RoadMode(); } else { Map.Mode = new AerialMode(true); } }
Press F5 to test the results. For switching views, click on the “eye” button on the application bar. This invokes the ChangeMapMode method.
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 MainPage 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.
To remove the Bing logo and Copyright from the bottom, you can set both Map.CopyrightVisibility and Map.LogoVisibility to Visibility.Collapsed.
<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 can’t change the buttons style or location. Next you will add custom zoom buttons so you can freely zoom in and out.
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 you’ve added and notify on property changed.
public double Zoom { get { return _zoom; } set { var coercedZoom = Math.Max(MinZoomLevel, Math.Min(MaxZoomLevel, value)); if (_zoom != coercedZoom) { _zoom = value; NotifyPropertyChanged("Zoom"); } } }
Open the MainPage.xaml in XAML editor and bind the Map.ZoomLevel property with the Zoom property you’ve just changed. The binding mode must be two-way.
<my:Map Name="Map" LogoVisibility="Collapsed" CopyrightVisibility="Collapsed" CredentialsProvider="{Binding CredentialsProvider}" ZoomLevel="{Binding Zoom, Mode=TwoWay}"> <my:Map.Mode> <my:AerialMode ShouldDisplayLabels="True" /> </my:Map.Mode> </my:Map>
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.
<my:Map Name="Map" LogoVisibility="Collapsed" CopyrightVisibility="Collapsed" CredentialsProvider="{Binding CredentialsProvider}" ZoomLevel="{Binding Zoom, Mode=TwoWay}"> <my:Map.Mode> <my:AerialMode ShouldDisplayLabels="True" /> </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>
Register the respective button Click event with the ButtonZoomIn_Click and ButtonZoomOut_Click event handlers. These event handlers are already provided in the MainPage.xaml.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.
<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" />
To change the look and feel of the zoom-in and zoom-out buttons, open the MainPage.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.
<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" />
To test the results, press F5 and click the zoom-in and zoom-out buttons.
In the next step you’ll center the map to your geographic location. Since this lab works with the emulator, you don’t have a real GPS device. So you’ll have to pre-define your geographic location using latitude and longitude coordinates.
You can determine your geographic location by browsing to
https://www.bing.com/maps, set your location, and then copy the Latitude and Longitude coordinates from the address bar.
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.
private static readonly GeoCoordinate DefaultLocation = new GeoCoordinate(47.639631, -122.127713);
In the MainPage.xaml.cs, create a property called Center that exposes the _center field. In the setter, call the notification change method.
public GeoCoordinate Center { get { return _center; } set { if (_center != value) { _center = value; NotifyPropertyChanged("Center"); } } }
In the MainPage.xaml, bind the Map.Center property with the Center property you’ve created. The binding mode must be two-way.
<my:Map Name="Map" CredentialsProvider="{Binding CredentialsProvider}" ZoomLevel="{Binding Zoom, Mode=TwoWay}" Center="{Binding Center, Mode=TwoWay}"> ... </my:Map>
In the MainPage.xaml.cs, find the CenterLocation method. The first application’s bar left button event handler calls this method. Change both Center and Zoom to defaults.
private void CenterLocation() { Center = DefaultLocation; Zoom = DefaultZoomLevel; }
To test the application, press F5 and click the application bar’s target icon on the left.This should zoom and center the map to the location provided by the DefaultLocation field.
Figure 10
Center and zoom map to default location
- This concludes the exercise.
The complete solution for this exercise is provided at the following location: Source\Ex1-TheBingMapControl\End.