Interactive Mapping Blog

Mapping Solutions News

Writing a Bing Maps location aware application for Windows Phone 7 Series

imageIf you have been keeping up with the news from Mix2010 and yesterdays’ keynote you will know a number of exciting things have been released for windows phone 7 series:

  • completely free developer tools
  • the windows 7 phone series beta sdk
  • lots of details about using silverlight and xna to develop phone applications

So what does that mean for Bing Map, will there be a new silverlight control for mobile? There may well be an update to better support mobile development but you can start right now using the current Bing Maps silverlight control and it works! To show you how here is a quick tutorial creating your first location aware Bing Maps phone application.

Prerequisites

Getting Started

Start by opening Visual Studio 2010 (or express as offered free in the sdk) and create a new project, selecting the “Windows Phone Application” project template.

image

Now add references to the Bing Maps silverlight control (usually found in C:\Program Files\Bing Maps Silverlight Control\V1\Libraries). You may find you need to also add a reference to System.Windows.Browser to get it to compile correctly (from c:\Program Files\Microsoft Silverlight\4.0.50303.0\).

Finally for the setup, add a reference to System.Device.Location.

Creating a Basic User Interface

Now we have the project created lets create a simple user interface in XAML that has a Bing Map Control, a status bar and a start button. First add the Bing Maps namespace to you MainPage.xaml file:

xmlns:m="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl"

Then add the following block of XAML in the grid named “ContentGrid” which should already be in MainPage.xaml:

  1. <m:Map Name="mapMain" NavigationVisibility="Collapsed" Mode="AerialWithLabels" CredentialsProvider="ADD_YOUR_BINGMAPS_KEY_HERE">
  2. </m:Map>
  3. <Border Background="Black" Height="40" Opacity="0.7" VerticalAlignment="Top">
  4.     <TextBlock Name="tbStatus" Text="Click below to start" Margin="5 5 0 0" />
  5.    </Border>

Now change the name of the application and the title to be whatever you want. Hit F5 and you should get the emulator load up with you application showing a Bing Map!"

Making it actually do something

For the next part of the tutorial we are going to make the application actually do something with the map by making it location aware, that is to say use the devices location to change the map in some way.

First add the following to your XAML just under the map control, to add a button:

  1. <Button Name="btnStart" Click="btnStart_Click" Width="260" Height="40">
  2.     <Button.Content>
  3.         <StackPanel Orientation="Horizontal">
  4.             <Path Fill="White" Data="F1 M 2.339,6.489 C 1.193,5.343 1.193,3.485 2.339,2.339 C 3.485,1.192 5.344,1.193 6.489,2.339 C 7.635,3.485 7.635,5.343 6.489,6.489 C 5.344,7.636 3.485,7.636 2.339,6.489 Z M 11.711,10.209 L 8.185,6.684 C 9.207,4.986 9.000,2.757 7.535,1.293 C 5.812,-0.431 3.017,-0.431 1.293,1.293 C -0.431,3.017 -0.431,5.812 1.293,7.536 C 2.757,8.999 4.988,9.206 6.685,8.185 L 10.209,11.710 L 11.711,10.209 Z" Margin="0,0,5,0">
  5.                 <Path.RenderTransform>
  6.                     <ScaleTransform ScaleX="2.5" ScaleY="2.5" />
  7.                 </Path.RenderTransform>
  8.             </Path>
  9.             <TextBlock Foreground="White" Text="Find Me Now" Margin="20 -5 0 0" />
  10.         </StackPanel>
  11.     </Button.Content>
  12. </Button>

 

Then and add a map layer with a simple circle pushpin to the map control:

  1.           <m:Map Name="mapMain" NavigationVisibility="Collapsed" Mode="AerialWithLabels" CredentialsProvider="ApXw1_p4abRAyITXFZGy6IvPyUN05hwF08hfkkNMUfExuujgB-XpmebygnDRH1RA">
  2.               <m:MapLayer Name="lMain">
  3.                   <Ellipse Fill="Red" Width="20" Height="20" m:MapLayer.Position="0,0" Name="ppLocation" Visibility="Collapsed" />
  4.                           </m:MapLayer>
  5.             </m:Map>

Now we are going to wire up the click event of the button to get the users location and update the map. We will do this in a number of stages.

Firstly, add these using statements to the top of your code:

  1. using System.Device.Location;
  2. using Microsoft.Maps.MapControl;

 

Now add a private member of type GeoCoordinateWatcher above the MainPage constructor:

  1. GeoCoordinateWatcher watcher;
  2. public MainPage()
  3. {
  4.     InitializeComponent();
  5.  
  6.     SupportedOrientations = SupportedPageOrientation.Portrait | SupportedPageOrientation.Landscape;
  7. }

And add the following event handler for the button click:

  1. private void btnStart_Click(object sender, RoutedEventArgs e)
  2. {
  3.     // Reinitialize the GeoCoordinateWatcher
  4.     watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
  5.     watcher.MovementThreshold = 100;//distance in metres
  6.  
  7.     // Add event handlers for StatusChanged and PositionChanged events
  8.     watcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged);
  9.     watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);
  10.  
  11.     // Start data acquisition
  12.     watcher.Start();
  13.  
  14.     //hide button
  15.     btnStart.Visibility = Visibility.Collapsed;
  16. }

This creates a new GeoCoordinateWatcher when the button is clicked with the accuracy set to high, sets a movement threshold allowing movement by 100 metres before the application is alerted and attaches two events. The first event “StatusChanged” will fire when the status of the location data changes (like during initialisation and once we have a location) and the second event handles changes to the current location. We will add the handlers for both in a minute. Lastly we start the watcher and hide the button then wire it up in the XAML to our recently added button’s click event:

  1. <Button Name="btnStart" Click="btnStart_Click" Width="260" Height="40">
  2.     <Button.Content>
  3.         <StackPanel Orientation="Horizontal">
  4.             <Path Fill="White" Data="F1 M 2.339,6.489 C 1.193,5.343 1.193,3.485 2.339,2.339 C 3.485,1.192 5.344,1.193 6.489,2.339 C 7.635,3.485 7.635,5.343 6.489,6.489 C 5.344,7.636 3.485,7.636 2.339,6.489 Z M 11.711,10.209 L 8.185,6.684 C 9.207,4.986 9.000,2.757 7.535,1.293 C 5.812,-0.431 3.017,-0.431 1.293,1.293 C -0.431,3.017 -0.431,5.812 1.293,7.536 C 2.757,8.999 4.988,9.206 6.685,8.185 L 10.209,11.710 L 11.711,10.209 Z" Margin="0,0,5,0">
  5.                 <Path.RenderTransform>
  6.                     <ScaleTransform ScaleX="2.5" ScaleY="2.5" />
  7.                 </Path.RenderTransform>
  8.             </Path>
  9.             <TextBlock Foreground="White" Text="Find Me Now" Margin="20 -5 0 0" />
  10.         </StackPanel>
  11.     </Button.Content>
  12. </Button>

 

Ok, the next piece of the puzzle is to add the event handlers we attached in the button click handler above, watcher_StatusChanged and watcher_PositionChanged:

  1. #region Event Handlers
  2.  
  3. /// <summary>
  4. /// Handler for the StatusChanged event. This invokes MyStatusChanged on the UI thread and
  5. /// passes the GeoPositionStatusChangedEventArgs
  6. /// </summary>
  7. /// <param name="sender"></param>
  8. /// <param name="e"></param>
  9. void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
  10. {
  11.     Deployment.Current.Dispatcher.BeginInvoke(() => MyStatusChanged(e));
  12.  
  13. }
  14.  
  15. /// <summary>
  16. /// Handler for the PositionChanged event. This invokes MyStatusChanged on the UI thread and
  17. /// passes the GeoPositionStatusChangedEventArgs
  18. /// </summary>
  19. /// <param name="sender"></param>
  20. /// <param name="e"></param>
  21. void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
  22. {
  23.     Deployment.Current.Dispatcher.BeginInvoke(() => MyPositionChanged(e));
  24. }
  25.  
  26. #endregion

You will notice these call two methods when they are triggered, but they ensure that these methods are called on the UI thread otherwise we will get some nasty cross thread errors.

Finally add the two UI thread methods for doing something when the events fire, and a simple ResetMap method that’s called when the user initially clicks the button:

  1. /// <summary>
  2. /// Custom method called from the PositionChanged event handler
  3. /// </summary>
  4. /// <param name="e"></param>
  5. void MyPositionChanged(GeoPositionChangedEventArgs<GeoCoordinate> e)
  6. {
  7.     // Update the map to show the current location
  8.     Location ppLoc = new Location(e.Position.Location.Latitude, e.Position.Location.Longitude);
  9.     mapMain.SetView(ppLoc, 10);
  10.  
  11.     //update pushpin location and show
  12.     MapLayer.SetPosition(ppLocation, ppLoc);
  13.     ppLocation.Visibility = System.Windows.Visibility.Visible;
  14.  
  15.     
  16. }
  17.  
  18. /// <summary>
  19. /// Custom method called from the StatusChanged event handler
  20. /// </summary>
  21. /// <param name="e"></param>
  22. void MyStatusChanged(GeoPositionStatusChangedEventArgs e)
  23. {
  24.     switch (e.Status)
  25.     {
  26.         case GeoPositionStatus.Disabled:
  27.             // The location service is disabled or unsupported.
  28.             // Alert the user
  29.             tbStatus.Text = "sorry we can’t find you on this device";
  30.             break;
  31.         case GeoPositionStatus.Initializing:
  32.             // The location service is initializing.
  33.             // Disable the Start Location button
  34.             tbStatus.Text = "looking for you…";
  35.             break;
  36.         case GeoPositionStatus.NoData:
  37.             // The location service is working, but it cannot get location data
  38.             // Alert the user and enable the Stop Location button
  39.             tbStatus.Text = "can’t find you yet…";
  40.             ResetMap();
  41.  
  42.             break;
  43.         case GeoPositionStatus.Ready:
  44.             // The location service is working and is receiving location data
  45.             // Show the current position and enable the Stop Location button
  46.             tbStatus.Text = "found you!";
  47.             break;
  48.  
  49.     }
  50. }
  51.  
  52. void ResetMap()
  53. {
  54.     Location ppLoc = new Location(0, 0);
  55.     mapMain.SetView(ppLoc, 1);
  56.  
  57.     //update pushpin location and show
  58.     MapLayer.SetPosition(ppLocation, ppLoc);
  59.     ppLocation.Visibility = System.Windows.Visibility.Collapsed;
  60. }

 

These first method MyPositionChanged updates the map by setting the current map view to the new location and zooming in. It also makes the pushpin icon visible. The second method MyStatusChanged simply updates the status text in the UI with a message telling the user the current state of the location services.

Houston we have a problem

By now you should have a finished application the compiles, if not you can download the source code below to see the full code:

butdownloadcode[1]

You can run the application in the emulator by clicking F5 and the map and UI should appear, BUT here we find a problem.

The emulator currently does not support the location service, so all we ever get back is a status change of NoData. There is currently not even any way to add fake data to the emulator so we will have to wait for an update to allow us to actually get location aware applications working in the emulator :-(

So until we can get our hands on some real hardware “Nudge, Nudge”  there is no real way to test this application.

21 Responses to “Writing a Bing Maps location aware application for Windows Phone 7 Series”

  1. Al Pascual Said on

    The bing map control is compiled in Silverlight not in Windows Phone 7 so cannot be used for me! :-(

  2. Duncan McGregor Said on

    I see Tim Heuer has published a demo that mocks location
    http://timheuer.com/blog/archive/2010/03/22/geo-location-services-in-windows-phone-7-developer-emulator.aspx

    hope this helps

  3. Playing with Windows Phone Developer Tools CTP : Al Pascual Said on

    [...] http://www.earthware.co.uk/blog/index.php/2010/03/writing-a-bing-maps-location-aware-application-for… [...]

  4. DotNetDevDude Said on

    Great article! The only thing you may want to mention is where to find the dll for System.Windows.Browser.

  5. Source Code : Windows Phone 7 Series Bing Maps location aware app | Free Pocket PC Software Said on

    [...] Get it from earthware.co.uk [...]

  6. Johan Lindfors Said on

    Great article, but you can actually mock the GeoCoordinateWatcher kind of elegantly as Tim Heuer demonstrates in this article:

    http://timheuer.com/blog/archive/2010/03/22/geo-location-services-in-windows-phone-7-developer-emulator.aspx?utm_source=Twitter-timheuer

  7. Gary Said on

    Thought this might’ve been possible.
    However the app only works for me in Debugging mode(F5) and not in Normal mode(CTRL-F5). In Normal mode, emulator remains blank . Strange !!.

  8. timheuer Said on

    Actually you can fake the geo data: http://timheuer.com/blog/archive/2010/03/22/geo-location-services-in-windows-phone-7-developer-emulator.aspx

  9. Silverlight and Windows Phone 7 Link Post » Gary Pretty’s Blog Said on

    [...] [...]

  10. Rongchaua's blog » Windows Phone – Embedded fonts and Bing maps Said on

    [...] that we can use embedded font and host a Bing map control. For Bing map example, I use this example http://www.earthware.co.uk/blog/index.php/2010/03/writing-a-bing-maps-location-aware-application-for… with some modifications so that I can relatively find my location on Bing [...]

  11. RaviKumar Said on

    Hi,
    Is it mentioned any where in the microsoft MSDN that, he emulator currently does not support the location service.

    Can you please refere me with that link…

    Thanks
    RK

  12. David Said on

    Can someone explain why the emulator cannot show the sample maps mentioned in this communication? I have the same problem as Gary had. I found the problem is caused by the “System.Windows.Browser”. If I remove the System.Windows.Browser reference, display can show up. However, the map control requires the System.Windows.Browser reference. Without it the map control cannot be used. As a result, I cannot make any of the samples work. Have I missed anything? Thanks.

    David R

  13. raangu Said on

    Hey,

    thanks for this tutorial, but a big white rectangle occurs everytime, anyone with the same problem?

    thanks

  14. Nashman Said on

    I am getting only blank screen on the emulator with latest CTP and bing silverlight control (7/23/2010)

  15. Kevin Said on

    Any chance that you will compile the app with the beta version and available for download? Thanks for the great work

  16. Michael Said on

    Adding a reference to System.Windows.Browser no longer fixing the problem with the bing maps control not compiling.

  17. Nicolas GUILLAUME Said on

    Hi,

    Thanks for this great tutorial but i was wondering …
    How did you generate the Path markup language for the magnifier icon ?

    Thanks.

  18. Windows Phone 7 linkek « einkalkstein blog Said on

    [...] http://www.earthware.co.uk/blog/index.php/2010/03/writing-a-bing-maps-location-aware-application-for… [...]

  19. Mike Said on

    I’m trying to use some of these samples, but getting an error when trying to call the setValue method on the MapLayer. I know in Windows Phone 7 there is not SetPosition or SetValue static method, so i am using the instance method:

    mlLayer1.SetValue(MapLayer.PositionProperty, loc);

    The run time exception on this line is “’10.748687,-10.985549,0′ is not a valid value for property ‘Position’.

    Any thoughts on this?

  20. Roch Said on

    Is there a way to have an embed map of bing using the bird’s eye view but zoomed out? The default zoom is too close and can’t really show the whole neighborhood.

  21. Alexandre Said on

    Hi… greate article but i have the same problem that Gary has..

    Thought this might’ve been possible.
    However the app only works for me in Debugging mode(F5) and not in Normal mode(CTRL-F5). In Normal mode, emulator remains blank . Strange !!.

    In the phone is the same situation.. only in degub mode.. works.. in normal mode the application try to open and close…
    What can be?