We continue our path on geolocation services, making a list of what were 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 in the order:

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. Be found 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 give something in terms of user experience. Imagine we have developed an application that makes use of the maps. The user is expected over the path displayed, even the text directions on how to reach the destination, in this case we Route and RouteLeg classes. The class Route exposes several properties with which will be able to give the user information additional to that of the route display. We analyze the properties one by one.

  • 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 and 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 through ownership Maneuvers class RouteLeg all the details to display text to the user, we will see shortly.

LenghtInMeters: property of type int indicates 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, 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, which represents the detail in text form which way to go to reach the destination, and the other LenghtInMeters properties that we have seen previously.



Implementation of classes and Route RouteLeg in the test project

After this brief introduction, and now 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, explores solutions we place the cursor on the file RouteTravel.xaml, double click with the mouse and replace the existing code with this:

<!--LayoutRoot è la griglia radice in cui viene inserito tutto il contenuto della pagina-->
< Gridx:Name="LayoutRoot"Background="Transparent">
 <Grid.RowDefinitions>
 <RowDefinitionHeight="Auto"/>
 <RowDefinitionHeight="*"/>
 </Grid.RowDefinitions>
 
 <!--TitlePanel contiene il nome dell'applicazione e il titolo della pagina-->
 <StackPanelGrid.Row="0"Margin="12,17,0,28">
 <TextBlockText="GeoPositionSample"Style="{StaticResource PhoneTextNormalStyle}"/>
 <!--<TextBlock Text="Route travel" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>-->
 </StackPanel>
 
 <!--ContentPanel - inserire ulteriore contenuto qui-->
 <Gridx:Name="ContentPanel"Grid.Row="1"Margin="12,0,12,0">
 <phone:Pivot>
  <phone:PivotItem>
  <Grid>
   <Grid.RowDefinitions>
   <RowDefinitionHeight="Auto"/>
   <RowDefinitionHeight="*"/>
   <RowDefinitionHeight="Auto"/>
   </Grid.RowDefinitions>
 
   <GridGrid.Row="0">
   <Grid.RowDefinitions>
    <RowDefinitionHeight="Auto"/>
    <RowDefinitionHeight="Auto"/>
    <RowDefinitionHeight="Auto"/>
    </Grid.RowDefinitions>
 
   <Grid.ColumnDefinitions>
    <ColumnDefinitionWidth="Auto"/>
    <ColumnDefinitionWidth="Auto"/>
    <ColumnDefinitionWidth="Auto"/>
   </Grid.ColumnDefinitions>
 
   <TextBlockGrid.Row="0"Grid.Column="0"Text="From"VerticalAlignment="Center"/>
   <TextBoxx:Name="tbxFrom"Text="My Position"IsEnabled="False"TextAlignment="Center"Grid.Row="0"Grid.Column="2"Width="400"/>
 
   <TextBlockGrid.Row="1"Grid.Column="0"Text="To"VerticalAlignment="Center"/>
   <TextBoxx:Name="tbxTo"Grid.Row="1"Grid.Column="2"Width="400"/>
   </Grid>
 
   <StackPanelGrid.Row="1">
   <Controls:Mapx:Name="mapLocation"Height="442"Width="480">
    <toolkit:MapExtensions.Children>
    <toolkit:Pushpinx:Name="myPushPinStart"Content="your are here"Visibility="Collapsed"/>
    <toolkit:Pushpinx:Name="myPushPinEnd"Content="destination"Visibility="Collapsed"/>
    </toolkit:MapExtensions.Children>
   </Controls:Map>
   </StackPanel>
 
   <ButtonGrid.Row="2"x:Name="btnFindCoordinate"Content="Find Route"Tap="btnFindCoordinate_Tap"/>
  </Grid>
  </phone:PivotItem>
   
  <phone:PivotItem>
  <Grid>
   <Grid.RowDefinitions>
    <RowDefinitionHeight="Auto"/>
   <RowDefinitionHeight="*"/>
   </Grid.RowDefinitions>
 
   <StackPanelGrid.Row="0"Orientation="Horizontal">
   <TextBlockText="Estimated duration"/>
   <TextBlock Text=":"Width="10"/>
   <TextBlockx:Name="tbkEstimatedDuration"/>
   </StackPanel>
 
  <ListBoxGrid.Row="1"x:Name="lstIstructionText">
    <ListBox.ItemTemplate>
    <DataTemplate>
    <Grid>
     <Grid.ColumnDefinitions>
      <ColumnDefinitionWidth="*"/>
      <ColumnDefinitionWidth="10"/>
      <ColumnDefinitionWidth="Auto"/>
     </Grid.ColumnDefinitions>
 
     <TextBlockGrid.Column="0"Text="{Binding InstructionText}"TextWrapping="Wrap"/>
     <TextBlockGrid.Column="1"/>
     <TextBlockGrid.Column="2"Text="{Binding LengthInMeters}"TextWrapping="Wrap"/>
     </Grid>
    </DataTemplate>
    </ListBox.ItemTemplate>
   </ListBox>
  </Grid>   
  </phone:PivotItem>
 </phone:Pivot>   
 </Grid>
< /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, while 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.

<
privateasync voidbtnFindCoordinate_Tap(objectsender, System.Windows.Input.GestureEventArgs e)
 {  
   var startPosition = await MyPosition.GetPosition();  
  MyPosition.FindRoute(tbxTo.Text, startPosition, mapLocation, lstIstructionText,tbkEstimatedDuration);
 }  

This is because we have added as a pivot 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 does is show 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.

public staticvoidFindRoute(stringposition, List<double> startposition, Map maps, ListBox travelinformation,TextBlock tbkestimatedduration)
{
 var locator = newGeolocator();
 var geocodequery = newGeocodeQuery();
 var coordinate = newList<GeoCoordinate>();
 var map = maps;
   if(!locator.LocationStatus.Equals(PositionStatus.Disabled))
 {
 try
 {
  geocodequery.GeoCoordinate = newGeoCoordinate(0, 0);
  geocodequery.SearchTerm = position;
  geocodequery.QueryAsync();
 
  geocodequery.QueryCompleted += (sender, args) =>
  {
  if(!args.Result.Equals(null))
  {
   var result = args.Result.FirstOrDefault();
   coordinate.Add(newGeoCoordinate(startposition[0], startposition[1]));
   coordinate.Add(newGeoCoordinate(result.GeoCoordinate.Latitude, result.GeoCoordinate.Longitude));
   var midLatitude = coordinate.Average(a => a.Latitude);
   var midLongitude = coordinate.Average(b => b.Longitude);
   map.Center = newGeoCoordinate(midLatitude, midLongitude);
   map.ZoomLevel = 12;
 
   RouteQuery query = newRouteQuery();
   query.TravelMode = TravelMode.Driving;
   query.RouteOptimization = RouteOptimization.MinimizeTime;
   query.Waypoints = coordinate;
 
   query.QueryCompleted += (senderone, argsone) =>
    {
    var maproute = newMapRoute(argsone.Result);
    map.AddRoute(maproute);
 
    var startpushpin = (Pushpin)maps.FindName("myPushPinStart");
    startpushpin.GeoCoordinate = newGeoCoordinate(startposition[0], startposition[1]);
    startpushpin.Visibility = System.Windows.Visibility.Visible;
 
    var endpushpin = (Pushpin)maps.FindName("myPushPinEnd");
    endpushpin.GeoCoordinate = newGeoCoordinate(coordinate[1].Latitude, coordinate[1].Longitude);
    endpushpin.Visibility = System.Windows.Visibility.Visible;
     Route route = argsone.Result;
    List<RouteInformation> travel = newList<RouteInformation>();  
    foreach(RouteLeg leg inroute.Legs)
    {
    for(var index = 0; index < leg.Maneuvers.Count; index++)
     {
     travel.Add(newRouteInformation
     {
      InstructionText = leg.Maneuvers[index].InstructionText,
     LengthInMeters = leg.Maneuvers[index].LengthInMeters.ToString() +"mt",
     EstimatedDuration = string.Concat(leg.EstimatedDuration.Hours.ToString(),"h","  ",leg.EstimatedDuration.Minutes.ToString() ,"m")
     });
    }
    }
 
    tbkestimatedduration.Text = travel[0].EstimatedDuration;
    travelinformation.ItemsSource = travel;
    };
 
   query.QueryAsync();
   }
  };
 }
 
 catch(Exception ex)
 {
  MessageBox.Show(ex.Message, AppResources.ApplicationTitle, MessageBoxButton.OK);
 }
 }
 
 else
 {
 MessageBox.Show("Service Geolocation not enabled!", AppResources.ApplicationTitle, MessageBoxButton.OK);
 }
}

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.

Route route = argsone.Result;
     List<RouteInformation> travel = newList<RouteInformation>();
     foreach(RouteLeg leg inroute.Legs)
     {
     for(var index = 0; index < leg.Maneuvers.Count; index++)
      {
      travel.Add(newRouteInformation
      {
       InstructionText = leg.Maneuvers[index].InstructionText,
       LengthInMeters = leg.Maneuvers[index].LengthInMeters.ToString() +"mt",
       EstimatedDuration = string.Concat(leg.EstimatedDuration.Hours.ToString(),"h","  ",leg.EstimatedDuration.Minutes.ToString() ,"m")
      });
      }
     }
 
     tbkestimatedduration.Text = travel[0].EstimatedDuration;
     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. The line of code below does is create a collection of type RouteInformation, where we are going to 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 debug our application, you must still create the class RouteInformation. In exploring solutions, we place the cursor on the name of the solution, the right mouse button, and choose the command "Add" and immediately after "Class". We call the file RouteInformation.cs, and insert the following code in it.

namespaceGeoPositionSample
{
 classRouteInformation
 {
 public stringInstructionText { get; set; }
 public stringLengthInMeters { get; set; }
 public stringEstimatedDuration { get; set; }
 }
}

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 latest travel time.

 


Test the application.

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

Image 1.2 The screen Route travel while running the application.

 

The screen consists of two TextBlock controls with 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 and the same in the previous article, but if we try to make a swipe the screen from right to left or from left to right, we realize that we have 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 control Maps on Windows Phone 8, but soon we'll see the control Maps on Windows Phone 8.1 and what are the differences.

 


Other Resources

Another important place to find a huge amount of Windows Phone related articles is the TechNet Wiki itself. The best entry point is   Windows Phone Resources on the TechNet Wiki