Before reading this article, I highly recommend reading the previous part:
Introduction
We continue our path with geolocation services, but making a guide to what we saw in the previous article on the control Nokia Maps. We analyzed the main functions, starting from the property ZoomLevel, able to change proportionally viewing the content on the map, then all the display types are available, from the Aerial Terrain. We saw other properties to provide more customization to the map, starting from the heading with which you can rotate the map of the center, ending with PedestrianFeaturesEnabled suitable when we walk. Finally was a brief introduction to what levels are, in other words the ability to create and superimpose the map of the custom layer, so as to display one or more points of interest, the whole with the class MapOverlay. This article will show how to insert one or more placeholders on the map, we will see that in the order:
- Placeholder generic
- Installing the Phone Toolkit
- Using the generic placeholder
- Test the generic placeholder
- Inserting more placeholder
- Test multiple placeholders
- Using the placeholder UserLocationMarker
- Test the control UserLocationMarker
- Conclusion
Remember to use the services of geolocation and maps; you must enable the capability ID_CAP_LOCATION and ID_CAP_MAP, discussed in previous articles found in the file WMAppManifest.xml (the features section).
Placeholder generic
As seen in the previous article, it is possible, by means of a layer, to customize the map view so the points of interest of our present position, all thanks to geolocation services. However, there are other ways to do this, the placeholder. There are two types, generic ones that will handle it in a short amount of code and those called UserLocationMarker. It is good to know that the SDK for Windows Phone 8 does not have these controls, you need to add them to the project with a reference to the Phone Toolkit for Windows Phone. The Phone Toolkit provides developers a series of controls, including an element called a pushpin. This control is what we will use to view our location on the map control. Nokia Maps offers various scenarios that we can implement within our application, a classic example is to calculate a route displayed on the map, but we see the main features in addition to the one just described.
Installing the Phone Toolkit
If available, we take over the project previously created with Visual Studio 2013, for those who have not had the opportunity to read the previous article, I leave the link to download the sample source code. We start Visual Studio 2013, the "File" menu select "Open" and immediately after "Project / Solution." For those who have downloaded the project from the preceding link, you go to select the file, depending on where you put it after you extracted the contents of the Zip file. Once you have opened the project, "explores solutions" we place the cursor on the "References", right-click and choose the command "Manage Nuget packages". We will use Nuget to install and add in the references of our project, the Windows Phone Toolkit. In the dialog that follows, we write Windows Phone Toolkit.
Image 1.1 The Phone Toolkit on Nuget.
After finding the library and clicking on the "Install" button, if all goes well, as shown in the figure, a green circle with a check mark in it means that it has been installed properly. We installed all you need; we look at what was added after installation of the Phone Toolkit.
Image 1.2 The Phone Toolkit in the references after installation.
We note that we have a new reference for our project: Microsoft.Phone.Controls.Toolkit. Let us examine the placeholders as anticipated previously available.
Using the generic placeholder
Let's go back to our project, we place the cursor on "GeoPositionSample", right-click, choose the command "Add", after "New Item", and choose the template "page vertical Windows Phone", as shown in the figure and call it PushPinSample.
Image 1.3 The Add new item screen.
We insert the following code, to define the graphical interface. Before namespaces.
- xmlns:Controls="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps"
It should be inserted immediately after.
- x:Class="GeoPositionSample.PushPinSample"
This will use the control NokiaMaps within the screen, otherwise we will get an error if we tried to compile the project, or not to print the local GUI properly. After defining the namespace, insert the following code.
- <!--LayoutRoot è la griglia radice in cui viene inserito tutto il contenuto della pagina-->
- <Grid x:Name="LayoutRoot" Background="Transparent">
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="*"/>
- </Grid.RowDefinitions>
-
- <!--TitlePanel contiene il nome dell'applicazione e il titolo della pagina-->
- <StackPanel Grid.Row="0" Margin="12,17,0,28">
- <TextBlock Text="GeoPositionSample" Style="{StaticResource PhoneTextNormalStyle}"/>
- <TextBlock Text="PushPin sample" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
- </StackPanel>
-
- <!--ContentPanel - inserire ulteriore contenuto qui-->
- <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
- <Grid.RowDefinitions>
- <RowDefinition Height="*"/>
- <RowDefinition Height="Auto"/>
- </Grid.RowDefinitions>
-
- <StackPanel>
- <Controls:Map x:Name="mapLocation" Height="442" Width="480">
- <toolkit:MapExtensions.Children>
- <toolkit:Pushpin x:Name="myPushPin" Content="your position" Visibility="Collapsed"/>
- </toolkit:MapExtensions.Children>
- </Controls:Map>
- </StackPanel>
-
- <Button Grid.Row="1" x:Name="btnFindCoordinate" Content="Find data" Tap="btnFindCoordinate_Tap"/>
- </Grid>
- </Grid>
If everything has been entered correctly, the screen will take on this aspect.
Image 1.4 The screen layout PushPinSample.
Defined graphical interface, we can handle everything you need for the inclusion of the generic placeholder. The first thing to do is to add the required namespace in file.xaml class pushpin.
- xmlns:toolkit="clr-namespace:Microsoft.Phone.Maps.Toolkit;assembly=Microsoft.Phone.Controls.Toolkit"
This is because the class PushPin is part of the namespace Microsoft.Phone.Maps.Toolkit. Later, in the XAML file of the screen, you need to add the property that we find in the toolkit, called MapExtensions. This is a holding area where all objects are grouped PhoneToolkit concerning controls Maps. We modify the code for controlling Maps as follows.
- <Controls:Map x:Name="mapLocation" Height="442" Width="480">
- <toolkit:MapExtensions.Children>
- <toolkit:Pushpin x:Name="myPushPin"/>
- </toolkit:MapExtensions.Children>
- </Controls:Map>
Afterb doing the change on the graphics, we should leave the management code behind. What we need to do is enhance the property GeoCoordinate with the latitude and longitude that now we know if we followed all the items up to now. Let's return to our project, we open the file named MyPosition.cs and insert the following code.
- public static async void MyPushPinPosition(Map maps)
- {
- var latitude = 0d;
- var longitude = 0d;
-
- try
- {
- var locator = new Geolocator();
-
- if (!locator.LocationStatus.Equals(PositionStatus.Disabled))
- {
- var position = await locator.GetGeopositionAsync();
- latitude = position.Coordinate.Latitude;
- longitude = position.Coordinate.Longitude;
-
- var pushpin = (Pushpin) maps.FindName("myPushPin");
- pushpin.GeoCoordinate = new GeoCoordinate(latitude, longitude);
- pushpin.Visibility = System.Windows.Visibility.Visible;
- maps.ZoomLevel = 19;
- maps.Center = new GeoCoordinate(latitude, longitude);
- }
-
- else
- {
- MessageBox.Show("Service Geolocation not enabled!", AppResources.ApplicationTitle, MessageBoxButton.OK);
- }
- }
-
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- }
- }
What we will do is, is nothing more than create a static method by prefixing the async keyword to the method signature, because this GetPositionAsync () is an asynchronous method. Let's see if the geolocation services are active, because the user can at any time turn them off. We check everything using this line of code:
- if (!locator.LocationStatus.Equals(PositionStatus.Disabled))
Checking the value of the enumerator PositionStatus, if different from Disabled, runs all the code inside the if block, otherwise notifies the user that geolocation services are disabled. This is also necessary to avoid an exception at runtime if you try to run the search with location services disabled. Then we call the method GetPositionAsync (), belonging to the class Geolocator that returns by the property Coordinate the latitude and longitude. Even this procedure should already be familiar because it has already been dealt with in the previous article. The news comes with these lines of code:
- var pushpin = (Pushpin) maps.FindName("myPushPin");
- pushpin.GeoCoordinate = new GeoCoordinate(latitude, longitude);
- pushpin.Visibility = System.Windows.Visibility.Visible;
The first is necessary to refer to the control Pushpin (generic placeholder), because being inside MapExtensions (in file.xaml), we cannot refer to it directly, but only by the method FindName () belonging to the control Maps. The second line of code does nothing but enhance the properties of the class GeoCoordinate pushpin with the latitude and longitude, to the location on the map. The last line of code simply makes visible the marker on the map, all setting the Visibility property with the value of the enumerator Visible Visibility. After this activity, one more thing is needed on the graphic: MainPage.xaml opens the file and adds this line of code just below the button btnLayers XAML code found inside the StackPanel control.
- <Button x:Name="btnPushPinSample" Content="PushPinSample" Tap="btnPushPinSample_Tap"/>
Image 1.5 The screen layout MainPage.
The last thing to do is to manage the navigation from MainPage to PushPinSample, we execute it using the Navigate method () of the property NavigationService belonging to the namespace System.Windows.Navigation. Open the file MainPage.xaml.cs and insert the following code.
- private void btnPushPinSample_Tap(object sender, System.Windows.Input.GestureEventArgs e)
- {
- NavigationService.Navigate(new Uri("/PushPinSample.xaml", UriKind.Relative));
- }
To tap on the button btnPushPinSample using the Navigate method (), we access the page PushPinSample. The method takes two arguments: the first, of type Uri where we will need to specify which page you want to access, in our case PushPinSample.xaml, the second is the type of navigation. We set the value Relative enumerator UriKind (all navigation among pages must be either Relative). After this activity, we are ready to run the application. F5 key, perform debugging and if there are no mistakes, this is the new home screen.
Image 1.6 The new home screen.
We note that we have the new button PushPinSample. We do a tap on it and we will be led into the new screen that we designed before.
Image 1.7 The screen image PushPinSample.
We have a Map control and a Button called Maps Find position. Now let's do a tap on the button and if everything is done correctly, this is the result of research position.
Image 1.8 The screen image PushPinSample after location research performed.
Inserting more placeholder
In this short procedure, it is seen as creating a placeholder, detect using geolocation services the user's location, the property value of the control GeoCoordinate pushpin and then show it on the map. However, there are cases where you need to specify multiple points of interest, as if we execute the download from a service on which we have more latitude and longitude coordinates to manage. The most suitable solution in this case, is to create the controls pushpin directly from code. Suppose you want to display a number of hotels in a specific area. We will create the first class, where we will gather all the necessary information. Let's go back to the project, we place the cursor on the project name in the Solution Explorer, right-click and select the command "Add" and immediately after "Class". We assign the name "Hotel" to the newly created class, after we replace the code with this.
- using System.Device.Location;
-
- namespace GeoPositionSample
- {
- class Hotel
- {
- public GeoCoordinate Coordinate { get; set; }
- public string NameHotel { get; set; }
- }
- }
It created a class called Hotel, defined a property of type GeoCoordinate that we will use later to assign values of latitude and longitude, another property of type string that we will use to show the name of the hotel on the map. With the same procedure that we used for the creation of the class hotel, instead we create a new page using the "New Item", using the template "page vertical Windows Phone", and we call it "MultiplePushpin" as shown in the figure.
Image 1.9 The Add new item screen.
Remaining in the XAML file, insert the following code to define the graphics, starting with the namespace needed, to use the map and controls Phone Toolkit.
- xmlns:Controls="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps"
- xmlns:toolkit="clr-namespace:Microsoft.Phone.Maps.Toolkit;assembly=Microsoft.Phone.Controls.Toolkit"
The rest defines the graphics.
- <!--LayoutRoot è la griglia radice in cui viene inserito tutto il contenuto della pagina-->
- <Grid x:Name="LayoutRoot" Background="Transparent">
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="*"/>
- </Grid.RowDefinitions>
-
- <!--TitlePanel contiene il nome dell'applicazione e il titolo della pagina-->
- <StackPanel Grid.Row="0" Margin="12,17,0,28">
- <TextBlock Text="GeoPositionSample" Style="{StaticResource PhoneTextNormalStyle}"/>
- <TextBlock Text="MultiplePushPin" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
- </StackPanel>
-
- <!--ContentPanel - inserire ulteriore contenuto qui-->
- <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
- <Grid.RowDefinitions>
- <RowDefinition Height="*"/>
- <RowDefinition Height="Auto"/>
- </Grid.RowDefinitions>
-
- <StackPanel>
- <Controls:Map x:Name="mapLocation" Height="442" Width="480">
- <toolkit:MapExtensions.Children>
- <toolkit:MapItemsControl>
- <toolkit:MapItemsControl.ItemTemplate>
- <DataTemplate>
- <toolkit:Pushpin
- x:Name="myPushPin"
- Content="{Binding NameHotel}"
- GeoCoordinate="{Binding Coordinate}"/>
- </DataTemplate>
- </toolkit:MapItemsControl.ItemTemplate>
- </toolkit:MapItemsControl>
- </toolkit:MapExtensions.Children>
- </Controls:Map>
- </StackPanel>
-
- <Button Grid.Row="1" x:Name="btnFindCoordinate" Content="Find Hotel" Tap="btnFindCoordinate_Tap"/>
- </Grid>
- </Grid>
If we remember the code of the screen PushPinSample, we will notice some changes as regards the map, in other words it defines a new object, MapItemsControl:
- <toolkit:MapItemsControl>
- <toolkit:MapItemsControl.ItemTemplate>
- <DataTemplate>
- <toolkit:Pushpin
- x:Name="myPushPin"
- Content="{Binding NameHotel}"
- GeoCoordinate="{Binding Coordinate}"/>
- </DataTemplate>
- </toolkit:MapItemsControl.ItemTemplate>
- </toolkit:MapItemsControl>
It is nothing more than a control that allows us to create a template, define the structure and eventually overlap with the map layers we're calling just as with the class MapOverlay. In our case, we have defined a DataTemplate inside, control pushpin, also note that compared first, the Content property and GeoCoordinate are binding with the properties that we have defined in the class Hotel. We shall not stop to explain what binding is, since it is beyond the scope of this article. We have also finished this activity, our screen should look like the following:
Image 1.10 The new screen MultiplePushPin.
After the part about the graphics, with the F7 key pass code editor. We will need to first add the namespace necessary to use all the functionality required.
- using Microsoft.Phone.Maps.Toolkit;
- using System.Collections.ObjectModel;
- using System.Device.Location;
The first namespace, you need to make use of the controls belonging to the Phone toolkit, the second will be used when we create a collection of type ObservableCollection to define all the data of the hotels, whereas the last is necessary to for using the geolocation services. We replace the code in the class with the following MultiplePushPin.
- using System.Linq;
- using System.Windows;
- using Microsoft.Phone.Controls;
- using Microsoft.Phone.Maps.Toolkit;
- using System.Collections.ObjectModel;
- using System.Device.Location;
-
- namespace GeoPositionSample
- {
- public partial class MultiplePushPin : PhoneApplicationPage
- {
- ObservableCollection<Hotel> Hotels = new ObservableCollection<Hotel>();
-
- public MultiplePushPin()
- {
- InitializeComponent();
- }
-
- private void btnFindCoordinate_Tap(object sender, System.Windows.Input.GestureEventArgs e)
- {
- Hotels.Add( new Hotel { Coordinate = new GeoCoordinate(45.07146, 7.68349), NameHotel = "Town House 70" });
- Hotels.Add( new Hotel { Coordinate = new GeoCoordinate(45.07257, 7.68411), NameHotel = "Hotel Chelsea" });
- Hotels.Add( new Hotel { Coordinate = new GeoCoordinate(45.07107, 7.68062), NameHotel = "Hotel Azalea" });
- Hotels.Add( new Hotel { Coordinate = new GeoCoordinate(45.06777, 7.68317), NameHotel = "Hotel San Carlo"});
- Hotels.Add( new Hotel { Coordinate = new GeoCoordinate(45.06714, 7.68516), NameHotel = "Hotel MioMay" });
-
-
- ObservableCollection<DependencyObject> hotels = MapExtensions.GetChildren(mapLocation);
-
- var result = hotels.FirstOrDefault(w => w.GetType().Equals(typeof(MapItemsControl))) as MapItemsControl;
- var midLatitude = Hotels.Average(a => a.Coordinate.Latitude);
- var midLongitude = Hotels.Average(b => b.Coordinate.Longitude);
-
- result.ItemsSource = Hotels;
- mapLocation.ZoomLevel = 16;
- mapLocation.Center = new GeoCoordinate(midLatitude, midLongitude);
- }
- }
- }
Was defined an ObservableCollection type Hotel, defining the coordinates of latitude and longitude, plus the name of the hotel with two properties exposed by the class Hotel. A clarification: it is not about dummy data but real, Hotel in the city of Turin. Inside the event tap the button btnFindCoordinate, is enhanced with the actual data collection Hotels. This is definitely the most interesting part:
- ObservableCollection<DependencyObject> hotels = MapExtensions.GetChildren(mapLocation);
-
- var result = hotels.FirstOrDefault(w => w.GetType().Equals(typeof(MapItemsControl))) as MapItemsControl;
- var midLatitude = Hotels.Average(a => a.Coordinate.Latitude);
- var midLongitude = Hotels.Average(b => b.Coordinate.Longitude);
-
- result.ItemsSource = Hotels;
- mapLocation.ZoomLevel = 16;
- mapLocation.Center = new GeoCoordinate(midLatitude, midLongitude);
Leveraging the MapExtensions class, we go to retrieve all the child elements within it using the method GetChildren (), then with the extension method FirstOrDefault recover the element MapItemsControl, valuing the ItemsSource property with the values of the ObservableCollection Hotels. Always with the extension method, in this case Average, perform average latitude and longitude and to exploit then the property of the Center Control Maps.
- mapLocation.Center = new GeoCoordinate(midLatitude, midLongitude);
Finally, we set the property value to ZoomLevel sixteen to always control Maps, to enlarge the display of points of interest. The last thing to do is to add in the MainPage the Button control for the navigation screen MultiplePushPin. Open the file MainPage.xaml and insert the following code inside the StackPanel control, where there is already code of the other buttons.
- <Button x:Name="btnMultiplePushPin" Content="Multiple push pin" Tap="btnMultiplePushPin_Tap"/>
F7 key, we enter in the code editor and manage the event Tap.
- private void btnMultiplePushPin_Tap(object sender, System.Windows.Input.GestureEventArgs e)
- {
- NavigationService.Navigate(new Uri("/MultiplePushPin.xaml", UriKind.Relative));
- }
This will be the new interface of the MainPage after the addition of the new button.
Image 1.11 new screens MainPage.
We can now test the application, F5 and start the debugging, we do a tap on the button Multiple push pin, entered the new screen, another tap on the button Find Hotel, if all goes well, this is how the map will look at the end of the search.
Image 1.12 map to search performed.
Using the placeholder UserLocationMarker
In some cases, the control pushpin is not ideal to report the location of the user, especially when moving. The Phone toolkit provides another placeholder, called UserLocationMarker. The management of this placeholder is nearly identical to the generic one. As we will see the changes to be made are really minimal. Let's go back to the project and open the file PushPinSample.xaml and modify the existing code
- <StackPanel>
- <Controls:Map x:Name="mapLocation" Height="442" Width="480">
- <toolkit:MapExtensions.Children>
- <toolkit:Pushpin x:Name="myPushPin" Content="your position" Visibility="Collapsed"/>
- </toolkit:MapExtensions.Children>
- </Controls:Map>
- </StackPanel>
With this following.
- <StackPanel>
- <Controls:Map x:Name="mapLocation" Height="442" Width="480">
- <toolkit:MapExtensions.Children>
- <toolkit:UserLocationMarker x:Name="myUserLocationMarker" Visibility="Collapsed"/>
- </toolkit:MapExtensions.Children>
- </Controls:Map>
- </StackPanel>
The only difference lies in the fact that we have changed the control, in other words from Pushpin to UserLocationMarker and removed the Content property, for the rest is the same as before. Open the file MyPosition and we're going to replace this piece of code in the method MyPushPinPositon ():
- var pushpin = (Pushpin)maps.FindName("myPushPin");
- pushpin.GeoCoordinate = new GeoCoordinate(latitude, longitude);
- pushpin.Visibility = System.Windows.Visibility.Visible;
With this.
- var userLocationMarker = (UserLocationMarker)maps.FindName("myUserLocationMarker");
- userLocationMarker.GeoCoordinate = new GeoCoordinate(latitude, longitude);
- userLocationMarker.Visibility = Visibility.Visible;
Even in this circumstance, the changes are really minimal, we change the variable name pushpin with userLocationMarker and we recover by the method FindName the control name or myUserLocationMarker, whereas the properties GeoCoordinate Visibility and remain identical to those of the control pushpin.
Test control UserLocationMarker
Perform these changes, we can again start debugging the application by pressing F5, MainPage screen, tap on the button PushPinSample and then tap on the Find button position. If everything was done correctly, this is how you present the map with the new control.
Image 1.13 The map control UserLocationMarker.
Conclusion
This article, it was explained what are placeholders, how to define, create and then superimpose the control NokiaMaps, but starting from the installation of Phone Toolkit, need to be able to make use. Later, with the control pushpin, was defined as display the user's location and for the signaling of multiple points of interest. Finally, we made a brief overview of what is control UserLocationMarker, also part of Phone Toolkit. In the next article, we will see how you can view a route on the map and how to calculate a route.