Since the birth of Google Maps in early 2005, the mapping systems have grown significantly and become part of the business in different ways. There are plenty of opportunities in connecting today's modern devices, equipped with GPS sensors, together with maps and it is the reason because Bing has continuously delivered new versions of its own mapping controls, from the web version to Silverlight and finally for the Windows Store apps.
This new release comes in a separate download that can be easily found using the Visual Studio's extension manager, but it requires some kind of attention given its nature of a C++ component.
Installing the Bing Maps SDK for Windows Store apps
As I said above, the Bing Maps SDK is a separate download, and it's easy to get it, directly inside the Visual Studio IDE. Once you opened Visual Studio, go to the Tools menu and select "Extensions and Updates". This opens a dialog that shows initially the installed packages but also offers the ability to search online for components to be installed. Selecting the "online" node on the left, and entering "bing maps" on the right, you will be briefly taken to the item that let you download and install the SDK.
At this point you can select the items (reported in the figure on the right side), and click install. The download is approximately of 40 MB and, at the end, the SDK is installed and ready to be used.
It's time now to create (or open) the project where you need to reference the map control. Once the project is open, you have to select the "References" node and, from the context menu select "Add reference...". From the Reference Manager dialog you have to select the "Windows" node and "Extensions". In the content pane it is listes a series of extension components and the Bing Maps should be there, under the name of "Bing Maps for C#, C++ or Visual Basic". If this does not happens please repeat the installation and double check if some error has occured.
Once you add the reference to the Bing Maps from here, you will notice that it also adds a reference to the "Microsoft Visual C++ Runtime Package". This reference is required because the bing maps are based of this runtime. The reference to this runtime has an important implication. If you try to run compilation just after having added it, this ends with an error:
Unfortunately, when you use Bing Maps - but also every other extension that is based on the Visual C++ runtime - you cannot use the "Any CPU" configuration but you are required to select one between x86, x64 or ARM. The choice has to be made on the base of the developing machine and the test device. As an example, if you need to debug on a Surface RT you have to select ARM and then deploy with the remote debugger. Differently it will not run. For this you have to pop out the Configuration Manager selecting it from the context menu of the solution explorer. Then select the choosen configuration and click OK.
Specify the Bing Maps credentials
Now that the project compiles correctly, it may be time to start using the control, but unfortunately there is another thing to do. Let's try to put the control in a page and see what it happen. First of all you add a namespace to the head of the page like this:
1: xmlns:map="using:Bing.Maps"
This let you use the mapping controls inside the application. So now you have to add the control to a grid so it takes all the available space in the page.
1: <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
2: <map:Map />
3: </Grid>
If you run the solution now, you will see the map working fine, with al the zoom and pan features but in the middle it appear a message like this: "The specified credentials are not valid. You can subscribe for a free developer account on the Bing portal". This happens because you do not have an account on the bing portal so, you have to connect to http://www.bingmapsportal.com and ask for a new account. The bing portal have the purpose of monitoring access to maps. In some versions there are some fees to pay when you use it in an intensive way, but as far as I know it is totally free when it is used by a Windows Store application. You are in charge of registering your application on the portal and it provides an alfanumeric string that you can put in the Credentials property. If the string match the portal, the control i authenticated and it start working without any additional message.
1: <Grid
2: Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
3: <map:Map Credentials="here goes the credential string provided by bing" />
4: </Grid>
Configuration and usage of the map.
Just before to start pointing coordinates on the map, you can also configure how it appears. There are a bunch of properties that are made to switch on or off features to bend the map to your will. Here is a list of properties that may be used for configuration purposes:
-
CopyrightPosition
-
LogoPosition
-
ScaleBarPosition
-
ShowBreadcrumb
-
ShowBuildings
-
ShowNavigationBar
-
ShowScaleBar
-
ShowTraffic
-
MapType
Most of them are self-describing. The first three determine the position of various elements like the bing logo, the scalebar and the copyright string. Some other are used to switch on or off elements. Finally the "MapType" let you specify the initial view that may be Aerial (with satellite imagery), road for maps and birdseye to have impressive 3D imagery taken by low quote flight. (have a look at Venice center for an example).
From the geographic point of view, you have a number of options to use the bing map control. You can use it simply to display a portion of a map, centering and zooming at your need, you can add PushPins, located at different positions and finally you can draw shapes on the base of geographic locations as you would do with a normal Canvas element. Starting from the beginning, you can easily position the map using the Center and ZoomLevel properties.
1: <map:Map ZoomLevel="15">
2: <map:Map.Center>
3: <map:Location Latitude="45.435" Longitude="12.333" />
4: </map:Map.Center>
5: </map:Map>
As you can see the center property is of type Location. This is a geographic entity that represents a single geographic point made of a Latitude and a Longitude. To set one or more PushPin at some given positions, you can use the PushPin element as a children of the map element. The elements inside are positioned using an attached property derived by the MapLayer element. So you have to use the MapLayer.Position at the same way you set Canvas.Top and Canvas.Left for the Canvas positioning.
1: <map:Map ZoomLevel="15">
2: <map:Map.Center>
3: <map:Location Latitude="45.435" Longitude="12.333" />
4: </map:Map.Center>
5:
6: <map:Pushpin>
7: <map:MapLayer.Position>
8: <map:Location Latitude="45.435" Longitude="12.333" />
9: </map:MapLayer.Position>
10: </map:Pushpin>
11: <map:Pushpin>
12: <map:MapLayer.Position>
13: <map:Location Latitude="45.445" Longitude="12.333" />
14: </map:MapLayer.Position>
15: </map:Pushpin>
16: <map:Pushpin>
17: <map:MapLayer.Position>
18: <map:Location Latitude="45.438" Longitude="12.315" />
19: </map:MapLayer.Position>
20: </map:Pushpin>
21:
22: </map:Map>
In this example I've set three PushPins over the map centered on Venice. They represents the center of the map and two arbitrary locations in the town. If you zoom the map in and out you will see the pushpins remaining at the same position and of the same size, no matter the zoom level of choice. You can also organize items in layers using the MapLayer element. A layer is a sort of group of elements that resides on the map and it is overlapped to all the other layers. The benefit of layers is that you can easily switch on or off every layer and all the elements inside of it.
1: <map:MapLayer Visibility="Visible">
2: <map:Pushpin>
3: <map:MapLayer.Position>
4: <map:Location Latitude="45.435" Longitude="12.333" />
5: </map:MapLayer.Position>
6: </map:Pushpin>
7: </map:MapLayer>
8: <map:MapLayer Visibility="Collapsed">
9: <map:Pushpin>
10: <map:MapLayer.Position>
11: <map:Location Latitude="45.445" Longitude="12.333" />
12: </map:MapLayer.Position>
13: </map:Pushpin>
14: </map:MapLayer>
15: p:Map>
The Visibility property here is able to hide the second layer in the example. Another interesting feature is the positioning of graphic shapes and xaml elements. Using the same attached property you can put on the map arbitrary shapes and locate them using a geographic position. In this example I display a circle located in place of a previous PushPin.
1: <map:MapLayer>
2: <Ellipse Width="100" Height="100" StrokeThickness="1" Stroke="#FFffffff" Fill="#88ff0000">
3: <map:MapLayer.Position>
4: <map:Location Latitude="45.435" Longitude="12.333" />
5: </map:MapLayer.Position>
6: </Ellipse>
7: </map:MapLayer>
Unfortunately there is not a way of making the size automatically adaptive on the basis of the zoom level. Since the width and height are specified in pixels you have to hookup the ViewChanged event and resize the element by yourself.
Display multiple items
When you use a map, there are few cases when you are limited to display only few points. In the greater number of cases you have to handle a number of positions and position them according to the position they have. Also you often need to change this position at a given time if the target has moved.
Also if you can for sure add programmatically these elements to the map, using the Children collection, you are probably use to data binding in your apps. When dealing with a moltitude of items to display you know you can use the ItemsControl and its derived classes so it is perfectly understandable you expect something similar with a map.
And it is exactly as you expect. The Map control let you use a special form of MapItemsControl to distribute elements using a geographic coordinate system. First of all configure the MapItemsControl in the XAML:
1: <map:Map>
2: <map:MapItemsControl x:Name="items">
3: <map:MapItemsControl.ItemTemplate>
4: <DataTemplate>
5: <Ellipse Width="100" Height="100" StrokeThickness="1" Stroke="#FFffffff" Fill="#88ff0000">
6: <map:MapLayer.Position>
7: <map:Location Latitude="{Binding Lat}" Longitude="{Binding Lon}" />
8: </map:MapLayer.Position>
9: </Ellipse>
10: </DataTemplate>
11: </map:MapItemsControl.ItemTemplate>
12: </map:MapItemsControl>
13: </map:Map>
The DataTemplate in this case contains a simple shape as in the previous example. It will be repeated for each instance in the collection binded to the ItemsSource property, as with a normal ItemsControl. In the following code I generate a number of random points and bind them to the MapItemsControl.
1: Random rnd = new Random(DateTime.Now.Millisecond);
2:
3: var data = (from i in Enumerable.Range(0, 10)
4: select new MapPoint
5: {
6: Lat = rnd.NextDouble() * 180 - 90,
7: Lon = rnd.NextDouble() * 360 - 180
8: })
9: .ToArray();
10:
11: items.ItemsSource = data;
As a result you will see ten ellipses displayed on the map. Please try to zoom in and out and let see how the map control acts. The items that exists the view are removed and its rendering is avoided. This, to maximize performances with a huge number of items.
About bugs and performances.
At the end of this fast overview of the Bing Maps controls I would like to warn you about some issues. I've used the control in my Earthquake Alerts app and I'm now aware that the control is unable to calculate regions when they cross the 180 degree of longitude. The control APIs have some useful methods to locate regions on the base of points and boundaries. Unfortunately if your range cross this line the map calculates it upside-down. This means that if you center the map on a region starting from +170 and ending to -170, it is calculated as it is starting at -170 and ending at +170 with the obvious error.
Another point to be care is about performances. Also if the control performs good with a number of points there is an upper limit that you have to avoid. Once you've added too much points to the map it starts to be slow, especially in zooming, because of the required amount of calculations needed to repositions all the elements. But once you aware of these limits, the control is for sure a great and easy opportunity to add maps to your own application.