The Nokia Maps on Windows Phone 8: Part 4

Before reading this article, I highly recommend reading the following previous parts:

Introduction

We continue our path on Geolocation Services, making a list of what we learned in the previous article. It was explained how you can view a route on the map and how to calculate a route, ending with managing the privacy policy on the user's location. In this fourth and final article we will see the following in the following order:
  • Introduction to the Route and RouteLeg classes
  • Implementation of the classes and Route RouteLeg in test project
  • Test the application
  • Conclusion
Remember to use the Geolocation Services and maps; you must enable the capability ID_CAP_LOCATION and ID_CAP_MAP, discussed in previous articles. They are in the file WMAppManifest.xml, the Features section.

Introduction to the Route and RouteLeg classes

In the last article we were able to track and view a route on the map, from the point of departure to arrival. A good result, but we can still provide something in terms of user experience. Imagine we have developed an application that uses maps. The user is expected over the path displayed, even the text directions on how to reach the destination, in this case we use the Route and RouteLeg classes. The class Route exposes several properties with which we will be able to provide the user information in addition to that of the route display. We analyze the properties one by one.

Class properties Route:
  • BoundingBox
  • EstimatedDuration
  • Geometry
  • Legs
  • LenghtInMeters
BoundingBox: it is a property of type LocationRectangle, the value of which is returned after the execution of the event QueryCompleted in a collection of type I<MapLocation>, it represents a portion of a map including the latitude longitude is, can then be displayed within the control Maps.

EstimatedDuration: TimeSpan property type, with which it can show the user the estimated travel time. Imagine a navigation system, where after route calculation it can show us the time needed to reach the destination of arrival.

Geometry: this property returns a collection of GeoCoordinate type, containing the latitude, longitude, height.

Legs: returns a collection type RouteLeg, where we will find, using the ownership Maneuvers class RouteLeg, all the details to display the text to the user, as we will see shortly.

LenghtInMeters: property of type int indicating the distance between a trip and another, for example when the navigation system pronunciation: "between 50 meters turn right." That "50" and ownership LenghtInMeters.

Concerning the class RouteLeg, the only difference compared to the class Route and the property Maneuvers is that we do not find in this class, but only within the class RouteLeg, while all the other properties remain such for both.

Maneuvers: This property gives us a collection of type RouteManeuvres where scrolling through all the elements of the collection are other properties, one of which (InstructionText) represents the detail in text form which way to go to reach the destination and the other LenghtInMeters properties that we saw previously.

Implementation of classes and Route RouteLeg in the test project.

That comletes the brief introduction. Now it is time to put into practice what has been said before. Let us pick up the project that we used in the third part on the control Maps. Find the complete example at this link. We open the project. To explore solutions we place the cursor on the file RouteTravel.xaml, double-click with the mouse and replace the existing code with this:
  1. <!--LayoutRoot è la griglia radice in cui viene inserito tutto il contenuto della pagina-->   
  2. < Grid x:Name="LayoutRoot" Background="Transparent">   
  3.     <Grid.RowDefinitions>   
  4.         <RowDefinition Height="Auto"/>   
  5.         <RowDefinition Height="*"/>   
  6.     </Grid.RowDefinitions>  
  7.     <!--TitlePanel contiene il nome dell'applicazione e il titolo della pagina-->   
  8.     <StackPanel Grid.Row="0" Margin="12,17,0,28">   
  9.         <TextBlock Text="GeoPositionSample" Style="{StaticResource PhoneTextNormalStyle}"/>   
  10.         <!--<TextBlock Text="Route travel" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>-->   
  11.     </StackPanel>  
  12.     <!--ContentPanel - inserire ulteriore contenuto qui-->   
  13.     <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">   
  14.         <phone:Pivot>   
  15.             <phone:PivotItem>   
  16.                 <Grid>   
  17.                      <Grid.RowDefinitions>   
  18.                         <RowDefinition Height="Auto"/>   
  19.                         <RowDefinition Height="*"/>   
  20.                         <RowDefinition Height="Auto"/>   
  21.                     </Grid.RowDefinitions>  
  22.                     <Grid Grid.Row="0">   
  23.                         <Grid.RowDefinitions>   
  24.                             <RowDefinition Height="Auto"/>   
  25.                              <RowDefinition Height="Auto"/>   
  26.                              <RowDefinition Height="Auto"/>   
  27.                          </Grid.RowDefinitions>  
  28.                         <Grid.ColumnDefinitions>   
  29.                             <ColumnDefinition Width="Auto"/>   
  30.                             <ColumnDefinition Width="Auto"/>   
  31.                             <ColumnDefinition Width="Auto"/>   
  32.                         </Grid.ColumnDefinitions>  
  33.                         <TextBlock Grid.Row="0" Grid.Column="0" Text="From" VerticalAlignment="Center"/>   
  34.                         <TextBox x:Name="tbxFrom" Text="My Position" IsEnabled="False" TextAlignment="Center" Grid.Row="0" Grid.Column="2" Width="400"/>  
  35.                         <TextBlock Grid.Row="1" Grid.Column="0" Text="To" VerticalAlignment="Center"/>   
  36.                         <TextBox x:Name="tbxTo" Grid.Row="1" Grid.Column="2" Width="400"/>   
  37.                     </Grid>  
  38.                     <StackPanel Grid.Row="1">   
  39.                         <Controls:Map x:Name="mapLocation" Height="442" Width="480">   
  40.                             <toolkit:MapExtensions.Children>   
  41.                                 <toolkit:Pushpin x:Name="myPushPinStart" Content="your are here" Visibility="Collapsed"/>   
  42.                                 <toolkit:Pushpin x:Name="myPushPinEnd" Content="destination" Visibility="Collapsed"/>   
  43.                             </toolkit:MapExtensions.Children>   
  44.                         </Controls:Map>   
  45.                      </StackPanel>  
  46.                     <Button Grid.Row="2" x:Name="btnFindCoordinate" Content="Find Route" Tap="btnFindCoordinate_Tap"/>   
  47.                 </Grid>   
  48.             </phone:PivotItem>   
  49.               
  50.             <phone:PivotItem>   
  51.                 <Grid>   
  52.                     <Grid.RowDefinitions>   
  53.                          <RowDefinition Height="Auto"/>   
  54.                         <RowDefinition Height="*"/>   
  55.                     </Grid.RowDefinitions>  
  56.                     <StackPanel Grid.Row="0" Orientation="Horizontal">   
  57.                         <TextBlock Text="Estimated duration"/>   
  58.                         <TextBlock  Text=":" Width="10"/>   
  59.                         <TextBlock x:Name="tbkEstimatedDuration"/>   
  60.                     </StackPanel>  
  61.                 <ListBox Grid.Row="1" x:Name="lstIstructionText">   
  62.                          <ListBox.ItemTemplate>   
  63.                             <DataTemplate>   
  64.                                 <Grid>   
  65.                                      <Grid.ColumnDefinitions>   
  66.                                          <ColumnDefinition Width="*"/>   
  67.                                          <ColumnDefinition Width="10"/>   
  68.                                          <ColumnDefinition Width="Auto"/>   
  69.                                      </Grid.ColumnDefinitions>  
  70.                                     <TextBlock Grid.Column="0" Text="{Binding InstructionText}" TextWrapping="Wrap"/>   
  71.                                      <TextBlock Grid.Column="1"/>   
  72.                                      <TextBlock Grid.Column="2" Text="{Binding LengthInMeters}" TextWrapping="Wrap"/>   
  73.                                  </Grid>   
  74.                             </DataTemplate>   
  75.                          </ListBox.ItemTemplate>   
  76.                     </ListBox>   
  77.                 </Grid>                          
  78.              </phone:PivotItem>   
  79.         </phone:Pivot>                         
  80.     </Grid>   
  81. < /Grid>  
If everything has been entered correctly, this will be the appearance of the screen RouteTravel.



Image 1.1 The screen Route travel.

It was redefined the GUI by adding a Pivot control, a sort of container with one or more tabs, where each tab is represented by a PivotItem. The screen 1.1 and included in the first PivotItem, whereas in the second we entered PivotItem a ListBox in binding with a class called RouteInformation, who will show in detail all the directions to the destination plus the estimated travel time. In RouteTravel.xaml.cs file, let's change the code of tap of the button btnFindCoordinate as follows.
  1. private async void btnFindCoordinate_Tap(object sender, System.Windows.Input.GestureEventArgs e)   
  2.      {            
  3.          var startPosition = await MyPosition.GetPosition();              
  4.          MyPosition.FindRoute(tbxTo.Text, startPosition, mapLocation, lstIstructionText,tbkEstimatedDuration);   
  5.      }  
This is because we have added as a pivot the said pivot with two items, one of which is the route to go in text form, so that we find in the method FindRoute MyPosition.cs file, add the reference of the ListBox lstIstructionText and TextBlock tbkEstimatedDuration that shows the estimated travel time to reach the destination. After this activity, we open the file MyPosition.cs and we modify the method FindRoute as follows.
  1. public static void FindRoute(string position, List<double> startposition, Map maps, ListBox travelinformation,TextBlock tbkestimatedduration)   
  2. {   
  3.     var locator = new Geolocator();   
  4.     var geocodequery = new GeocodeQuery();   
  5.     var coordinate = new List<GeoCoordinate>();   
  6.     var map = maps;  
  7.   
  8.     if (!locator.LocationStatus.Equals(PositionStatus.Disabled))   
  9.     {   
  10.         try   
  11.         {   
  12.             geocodequery.GeoCoordinate = new GeoCoordinate(0, 0);   
  13.             geocodequery.SearchTerm = position;   
  14.             geocodequery.QueryAsync();  
  15.             geocodequery.QueryCompleted += (sender, args) =>   
  16.             {   
  17.                 if (!args.Result.Equals(null))   
  18.                 {   
  19.                     var result = args.Result.FirstOrDefault();   
  20.                     coordinate.Add(new GeoCoordinate(startposition[0], startposition[1]));   
  21.                     coordinate.Add(new GeoCoordinate(result.GeoCoordinate.Latitude, result.GeoCoordinate.Longitude));  
  22.   
  23.                      var midLatitude = coordinate.Average(a => a.Latitude);   
  24.                     var midLongitude = coordinate.Average(b => b.Longitude);   
  25.                     map.Center = new GeoCoordinate(midLatitude, midLongitude);   
  26.                     map.ZoomLevel = 12;  
  27.                     RouteQuery query = new RouteQuery();   
  28.                      query.TravelMode = TravelMode.Driving;   
  29.                      query.RouteOptimization = RouteOptimization.MinimizeTime;   
  30.                     query.Waypoints = coordinate;  
  31.                     query.QueryCompleted += (senderone, argsone) =>   
  32.                          {   
  33.                             var maproute = new MapRoute(argsone.Result);   
  34.                             map.AddRoute(maproute);  
  35.                             var startpushpin = (Pushpin)maps.FindName("myPushPinStart");   
  36.                              startpushpin.GeoCoordinate = new GeoCoordinate(startposition[0], startposition[1]);   
  37.                             startpushpin.Visibility = System.Windows.Visibility.Visible;  
  38.                             var endpushpin = (Pushpin)maps.FindName("myPushPinEnd");   
  39.                             endpushpin.GeoCoordinate = new GeoCoordinate(coordinate[1].Latitude, coordinate[1].Longitude);   
  40.                             endpushpin.Visibility = System.Windows.Visibility.Visible;  
  41.   
  42.                             Route route = argsone.Result;   
  43.                             List<RouteInformation> travel = new List<RouteInformation>();  
  44.   
  45.                              foreach (RouteLeg leg in route.Legs)   
  46.                              {   
  47.                                 for (var index = 0; index < leg.Maneuvers.Count; index++)   
  48.                                  {   
  49.                                     travel.Add(new RouteInformation   
  50.                                     {   
  51.                                          InstructionText = leg.Maneuvers[index].InstructionText,   
  52.                                         LengthInMeters = leg.Maneuvers[index].LengthInMeters.ToString() + "mt",   
  53.                                         EstimatedDuration = string.Concat(leg.EstimatedDuration.Hours.ToString(),"h""  ",leg.EstimatedDuration.Minutes.ToString() ,"m")   
  54.                                      });   
  55.                                 }   
  56.                              }  
  57.                             tbkestimatedduration.Text = travel[0].EstimatedDuration;   
  58.                              travelinformation.ItemsSource = travel;   
  59.                          };  
  60.                     query.QueryAsync();   
  61.                  }   
  62.             };   
  63.         }  
  64.         catch (Exception ex)   
  65.         {   
  66.             MessageBox.Show(ex.Message, AppResources.ApplicationTitle, MessageBoxButton.OK);   
  67.         }   
  68.     }  
  69.     else   
  70.     {   
  71.         MessageBox.Show("Service Geolocation not enabled!", AppResources.ApplicationTitle, MessageBoxButton.OK);   
  72.     }   
  73. }   
By analyzing the code, if we followed the previous article, we will see over the addition of references to the ListBox and TextBlock as parameters to the method, we will have some new lines of C # code.
  1. Route route = argsone.Result;   
  2.                                      List<RouteInformation> travel = new List<RouteInformation>();  
  3.   
  4.                                     foreach (RouteLeg leg in route.Legs)   
  5.                                      {   
  6.                                         for (var index = 0; index < leg.Maneuvers.Count; index++)   
  7.                                          {   
  8.                                              travel.Add(new RouteInformation   
  9.                                              {   
  10.                                                  InstructionText = leg.Maneuvers[index].InstructionText,   
  11.                                                  LengthInMeters = leg.Maneuvers[index].LengthInMeters.ToString() + "mt",   
  12.                                                  EstimatedDuration = string.Concat(leg.EstimatedDuration.Hours.ToString(),"h""  ",leg.EstimatedDuration.Minutes.ToString() ,"m")   
  13.                                              });   
  14.                                          }   
  15.                                     }  
  16.                                     tbkestimatedduration.Text = travel[0].EstimatedDuration;   
  17.                                     travelinformation.ItemsSource = travel;  
These are the classes referred discussed earlier, in other words Route and RouteLeg. We declare a variable of type Route named route and assign the value of the Result parameter argsone type RouteQuery. What the line of code below does is create a collection of type RouteInformation, where we will enhance the properties InstructionText, LenghtInMeters and EstimatedDuration respectively with the values contained in the property belonging to the class Maneuvers RouteLeg leg, resulting in the text directions, the distance to go from one point to the other's path and estimated travel time. Prior to debugging our application, you must still create the class RouteInformation. In exploring solutions, we place the cursor on the name of the solution, click the right mouse button and choose the command "Add" and immediately after that select "Class". We call the file RouteInformation.cs and insert the following code into it.
  1. namespace GeoPositionSample   
  2. {   
  3.     class RouteInformation   
  4.     {   
  5.         public string InstructionText { getset; }   
  6.         public string LengthInMeters { getset; }   
  7.         public string EstimatedDuration { getset; }   
  8.     }   
  9. }  
We have defined a class that contains three properties of type string, the first is the text instructions of the route, the second the length in meters to go from one point to the other, while the late is the travel time.

Test the application

We included everything you need to view a route on the control Maps and more detail of which way to go. Press the F5 key and so we start debugging. The main screen remains the same as the last time. We tap on the last button and we will be led to the following screen.



Image 1.2 The screen Route travel when running the application.

The screen consists of two TextBlock controls with the values "Form" that is our position, "To" where we will enter the destination you want to view, control Maps on which will track the path that we display and finally a button called "Find route" that the tap will execute the code that we saw earlier. Now we type a location in the TextBox beside the word "To" as shown in the figure.



Image 1.3 The screen Route travel with the destination "Lerici, La Spezia".

After entering the destination, we tap on the button Find Route and if everything is done correctly, here is what will be the result on the map.



Image 1.4 The screen Route travel with the path displayed on the map.

Everything up to now is the same as in the previous article but if we try to swipe the screen from right to left or from left to right, we realize that we have a detailed textual itinerary to be ahead, with the travel time for each route, with top the estimated travel time, all visible as images.



Image 1.5 The screen Route travel with the first part of the detail text to go.

By scrolling down we will be able to view all the other information.



Image 1.6 The screen Route travel with the second part of the detail text to go.

Conclusion

In this article, it was explained the operation of the Route and RouteLeg classes, what are the main properties that expose these classes, we saw how to implement them and later view all the detailed text of the itinerary, including travel times for each route and display the estimated running time. With this article we finished everything related to the Maps control on Windows Phone 8, but soon we'll see the control Maps on Windows Phone 8.1 and what the differences are.