Blog technique sur mes expériences de développeur.
19 février 2013
Dans ce nouvel article sur Windows Phone 7, je vous propose de voir assemble comment afficher des itinéraires dans vos applications grâce aux services Microsoft.
L’application que nous allons produire sera constituée d’un pivot et de trois items :
L’écran de saisie est assez simple puisqu’il consiste à simplement afficher deux champs de saisie et un bouton :
<controls:PivotItem Header="Ecran de saisie">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="70"/>
<RowDefinition Height="70"/>
<RowDefinition Height="70"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Margin="10,0,0,0" Text="Départ : " VerticalAlignment="Center" />
<TextBox Grid.Row="0" Grid.Column="1" Width="360" Name="txtDepart" />
<TextBlock Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" Margin="10,0,0,0" Text="Arrivée :" VerticalAlignment="Center" />
<TextBox Grid.Row="1" Grid.Column="1" Width="360" Name="txtArrivee" />
<Button Grid.Row="2" Grid.ColumnSpan="2" Name="btnRecherche" Content="Rechercher" Click="btnRecherche_Click" />
</Grid>
</controls:PivotItem>
Le code behind quant à lui consiste simplement à vérifier que les champs ne sont pas vide avant de lancer la recherche :
private void btnRecherche_Click(object sender, RoutedEventArgs e)
{
if (txtDepart.Text == "")
{
MessageBox.Show("Merci de saisir un lieu de départ");
}
else if (txtArrivee.Text == "")
{
MessageBox.Show("Merci de saisir un lieu d'arrivée");
}
else
{
//On lance la recherche
}
}
Avant de faire la recherche, je vous propose de mettre en place l’écran qui accueillera la carte sur laquelle l’itinéraire sera tracée. Il s’agit d’une simple carte Bing. Pour plus d’information sur la carte et comment récupérer une clef, vous pouvez lire cet article.
<controls:PivotItem Header="Carte">
<Grid>
<my:Map HorizontalAlignment="Left" Name="mapItineraire" VerticalAlignment="Top" Width="455" Height="600" CopyrightVisibility="Collapsed" LogoVisibility="Collapsed" ZoomLevel="10" ZoomBarVisibility="Visible">
<my:Map.CredentialsProvider>
<my:ApplicationIdCredentialsProvider ApplicationId="Au..." />
</my:Map.CredentialsProvider>
<my:Map.Center>
<my1:GeoCoordinate Altitude="NaN" Course="NaN" HorizontalAccuracy="NaN" Latitude="47.64483" Longitude="-122.141197" Speed="NaN" VerticalAccuracy="NaN" />
</my:Map.Center>
</my:Map>
</Grid>
</controls:PivotItem>
Le calcul de l’itinéraire va se faire en trois étapes :
Pour récupérer les coordonnées GPS des points de départ et d’arrivée, nous allons utiliser le service Microsoft Geocode tandis que le service Route sera utilisé pour le calcul de l’itinéraire à proprement parlé.
Pour pouvoir les utiliser, nous devons ajouter des références à ces services dans notre projet. Pour ce faire, rendez-vous dans le menu Projet puis Ajouter une référence de service. La fenêtre suivante doit alors s’afficher à l’écran :
Pour le service Geocode voici les informations à saisir :
A noter que c’est vous qui décidez de l’espace de nom !
Pour le service Routevoici les informations à saisir :
Nous allons avoir besoin de quatre attributs faisant référence au service Geocode, à la requête au service, ainsi que deux attributs qui stockeront les coordonnées GPS des points de départ et d’arrivée :
private GeocodeServiceClient geocodeService;
private GeocodeRequest geocodeReq;
private GeocodeResult geocodeResDepart;
private GeocodeResult geocodeResArrivee;
Il convient maintenant de les** instancier** dans la méthode OnNavigatedTo :
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
//On instancie le service
geocodeService = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
geocodeService.GeocodeCompleted += geocodeService_GeocodeCompleted;
//On instancie la requête
geocodeReq = new GeocodeRequest();
geocodeReq.Credentials = new Credentials() { ApplicationId = "As..." };
}
A noter que l’applicationId est la clef de votre carte Bing.
Il est maintenant temps de lancer la requête. Pour ça, nous allons mettre à jour la méthode btnRecherche_click :
private void btnRecherche_Click(object sender, RoutedEventArgs e)
{
if (txtDepart.Text == "")
{
MessageBox.Show("Merci de saisir un lieu de départ");
}
else if (txtArrivee.Text == "")
{
MessageBox.Show("Merci de saisir un lieu d'arrivée");
}
else
{
//On indique que l'application tourne
progressIndicator.IsVisible = true;
//On lance la recherche
geocodeReq.Query = txtDepart.Text;
geocodeService.GeocodeAsync(geocodeReq);
}
}
Une fois que la recherche est terminée, c’est la méthode geocodeService_GeocodeCompleted qui est appelée comme nous l’avons indiqué pendant l’instanciation de notre objet.
Voici le détail de la méthode :
private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
if (e.Result != null && e.Result.Results.Any(x => x.Locations != null && x.Locations.Any()))
{
geocodeResDepart = e.Result.Results.FirstOrDefault();
}
else
{
MessageBox.Show("Impossible de localiser le départ");
}
}
Nous allons maintenant procéder à la récupération des coordonnées GPS du point d’arrivée. Nous allons lancer cette recherche uniquement en cas de réussite de la récupération des coordonnées GPS du point de départ.
Cette recherche va donc se faire dans la méthode geocodeService_GeocodeCompleted :
private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
if (e.Result != null && e.Result.Results.Any(x => x.Locations != null && x.Locations.Any()))
{
//On récupère les coordonnées du point de départ
geocodeResDepart = e.Result.Results.FirstOrDefault();
//On lance la recherche pour le point d'arrivée
geocodeReq.Query = txtArrivee.Text;
geocodeService.GeocodeAsync(geocodeReq);
}
else
{
MessageBox.Show("Impossible de localiser le départ");
}
}
Puisque cette méthode est encore appelée une fois le résultat trouvé, il convient de la modifier encore pour différencier son appel pour les coordonnées du point de départ ou d’arrivée. Pour se faire, nous allons créer un attribut qui nous permettra de savoir où nous en sommes.
Déclaration de l’attribut :
private string query;
Modification de la méthode btnRecherche_click :
private void btnRecherche_Click(object sender, RoutedEventArgs e)
{
if (txtDepart.Text == "")
{
MessageBox.Show("Merci de saisir un lieu de départ");
}
else if (txtArrivee.Text == "")
{
MessageBox.Show("Merci de saisir un lieu d'arrivée");
}
else
{
//On indique que l'application tourne
progressIndicator.IsVisible = true;
//On indique le type de la requête
query = "depart";
//On lance la recherche
geocodeReq.Query = txtDepart.Text;
geocodeService.GeocodeAsync(geocodeReq);
}
}
On modifie maintenant la méthode geocodeService_GeocodeCompleted :
private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
if (e.Result != null && e.Result.Results.Any(x => x.Locations != null && x.Locations.Any()))
{
if (query == "depart")
{
//On récupère les coordonnées du point de départ
geocodeResDepart = e.Result.Results.FirstOrDefault();
//On indique le type de la nouvelle requête
query = "arrivee";
//On lance la recherche pour le point d'arrivée
geocodeReq.Query = txtArrivee.Text;
geocodeService.GeocodeAsync(geocodeReq);
}
else
{
//On récupère les coordonnées du point d'arrivée
geocodeResArrivee = e.Result.Results.FirstOrDefault();
}
}
else
{
if (query == "depart")
{
MessageBox.Show("Impossible de localiser le départ");
}
else
{
MessageBox.Show("Impossible de localiser l'arrivée");
}
}
}
Maintenant que nous connaissons les coordonnées de nos points de départ et d’arrivée, nous allons procéder au calcul de l’itinéraire. Pour se faire, commencez par ajouter l’attribut suivant :
private RouteServiceClient routeService;
Mettez ensuite à jour la méthode OnNavigatedTo pour instancier notre attribut RouteServiceClient :
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
//On instancie les services
geocodeService = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
geocodeService.GeocodeCompleted += geocodeService_GeocodeCompleted;
routeService = new RouteServiceClient("BasicHttpBinding_IRouteService");
//On instancie la requête
geocodeReq = new GeocodeRequest();
geocodeReq.Credentials = new Credentials() { ApplicationId = "Au..." };
}
Nous allons maintenant créer une méthode CalculItineraire à appeler lorsque les coordonnées du point d’arrivée ont été trouvées. Voici le contenu commenté de notre méthode :
private void calculItineraire()
{
//On instancie la requête
RouteRequest routeReq = new RouteRequest();
routeReq.Credentials = new Credentials() { ApplicationId = "Au..." };
//Points de départ et d'arrivée de l'itinéraire
Waypoint wayPointDepart = new Waypoint() { Location = new Location() { Longitude = geocodeResDepart.Locations.FirstOrDefault().Longitude, Latitude = geocodeResDepart.Locations.FirstOrDefault().Latitude }, Description = geocodeResDepart.DisplayName };
Waypoint wayPointArrivee = new Waypoint() { Location = new Location() { Longitude = geocodeResArrivee.Locations.FirstOrDefault().Longitude, Latitude = geocodeResArrivee.Locations.FirstOrDefault().Latitude }, Description = geocodeResArrivee.DisplayName };
//On précise les points les lequels on veut passer dans l'itinéraire
routeReq.Waypoints = new ObservableCollection<Waypoint>();
routeReq.Waypoints.Add(wayPointDepart);
routeReq.Waypoints.Add(wayPointArrivee);
//Quelques options...
routeReq.Options = new RouteOptions() { Mode = TravelMode.Driving, RoutePathType = RoutePathType.Points };
routeReq.Culture = "FR-fr";
//On détermine la méthode à appeler quand cla recherche est terminée
routeService.CalculateRouteCompleted += routeService_CalculateRouteCompleted;
//On lance la recherche
routeService.CalculateRouteAsync(routeReq);
}
Une fois le calcul de l’itinéraire lancé, il convient d’implémenter la méthode à appeler une fois les résultats trouvés :
private void routeService_CalculateRouteCompleted(object sender, CalculateRouteCompletedEventArgs e)
{
if (e.Result != null && e.Result.Result != null && e.Result.Result.Legs != null && e.Result.Result.Legs.Any())
{
//Pushpin pour marquer le début et la fin du trajet
Pushpin pinDepart = new Pushpin() { Location = new GeoCoordinate(geocodeResDepart.Locations.FirstOrDefault().Latitude, geocodeResDepart.Locations.FirstOrDefault().Longitude), Content = "Début" };
Pushpin pinArrivee = new Pushpin() { Location = new GeoCoordinate(geocodeResArrivee.Locations.FirstOrDefault().Latitude, geocodeResArrivee.Locations.FirstOrDefault().Longitude), Content = "Fin" };
//On fait le tracé
var locationLst = new LocationCollection();
foreach (Location loc in e.Result.Result.RoutePath.Points)
{
locationLst.Add(new GeoCoordinate(loc.Latitude, loc.Longitude));
}
MapPolyline polyline = new MapPolyline() { Stroke = new SolidColorBrush(Colors.Blue), StrokeThickness = 5, Locations = locationLst };
//On ajouter les pushpin et le tracé sur la carte
mapItineraire.Children.Add(pinArrivee);
mapItineraire.Children.Add(pinDepart);
mapItineraire.Children.Add(polyline);
//On centre la carte sur le départ
mapItineraire.SetView(pinDepart.Location, 10);
}
else
{
MessageBox.Show("Impossible de calculer l'itinéraire");
}
}
Cet écran peut-être découpé en deux :
Avant toute chose, nous allons donc créer une classe nous permettant de modéliser une étape de l’itinéraire :
namespace Blog_Itineraire
{
public class ItineraireEtape
{
public string temps { get; set; }
public string distance { get; set; }
public string instruction { get; set; }
}
}
Le XAML quant à lui ressemble donc à ça :
<controls:PivotItem Header="Détails">
<StackPanel>
<TextBlock Name="lblDepart" />
<TextBlock Name="lblArrivee" />
<TextBlock Name="lblDistance" />
<TextBlock Name="lblTemps" />
<ListBox Name="lstBoxItineraire" Height="480" Margin="0,20,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Grid Width="440">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding temps}" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" />
<TextBlock Text="{Binding distance}" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Right" />
<TextBlock Text="{Binding instruction}" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" TextWrapping="Wrap" Margin="0,10,0,0" />
</Grid>
<Rectangle Fill="White" Height="1" Margin="0,10" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</controls:PivotItem>
Dans le code behind, nous allons créer une méthode afficherItineraire qui prend en paramètre e.Result.Result.Legs.FirstOrDefault() où e est le CalculateRouteCompletedEventArgs de la méthode routeService_CalculateRouteCompleted.
Comme vous allez pouvoir le remarquer, j’ai également créé deux fonctions me permettant de supprimer les morceaux de XML du détail des itinéraires et de convertir les secondes en heure et minutes.
private void afficherItineraire(RouteLeg leg)
{
//Infos générales
lblDepart.Text = "Départ : " + geocodeResDepart.DisplayName;
lblArrivee.Text = "Arrivée : " + geocodeResArrivee.DisplayName;
lblDistance.Text = "Distance : " + leg.Summary.Distance + " km";
lblTemps.Text = "Temps : " + ConvertirTemps(leg.Summary.TimeInSeconds);
//Les étapes
List<ItineraireEtape> lstSteps = new List<ItineraireEtape>();
foreach (ItineraryItem item in leg.Itinerary)
{
lstSteps.Add(new ItineraireEtape() { temps = ConvertirTemps(item.Summary.TimeInSeconds), distance = item.Summary.Distance.ToString() + " km", instruction = ParseItineraire(item.Text) });
}
lstBoxItineraire.ItemsSource = lstSteps;
//On stoppe l'indicateur
progressIndicator.IsVisible = false;
}
private string ParseItineraire(string itemText)
{
//On enlève les morceaux de XML
itemText = itemText.Replace("<VirtualEarth:Action>", "");
itemText = itemText.Replace("</VirtualEarth:Action>", "");
itemText = itemText.Replace("<VirtualEarth:TurnDir>", "");
itemText = itemText.Replace("</VirtualEarth:TurnDir>", "");
itemText = itemText.Replace("<VirtualEarth:Toward>", "");
itemText = itemText.Replace("</VirtualEarth:Toward>", "");
itemText = itemText.Replace("<VirtualEarth:RoadName>", "");
itemText = itemText.Replace("</VirtualEarth:RoadName>", "");
itemText = itemText.Replace("<VirtualEarth:ExitNumber>", "");
itemText = itemText.Replace("</VirtualEarth:ExitNumber>", "");
itemText = itemText.Replace("<VirtualEarth:Sign>", "");
itemText = itemText.Replace("</VirtualEarth:Sign>", "");
itemText = itemText.Replace("<VirtualEarth:WaypointName>", "");
itemText = itemText.Replace("</VirtualEarth:WaypointName>", "");
return itemText;
}
private string ConvertirTemps(long timeInSeconds)
{
TimeSpan timeSpan = TimeSpan.FromSeconds(timeInSeconds);
if (timeSpan.Hours != 0)
{
return string.Format("{0:D2}h{1:D2}min", timeSpan.Hours, timeSpan.Minutes);
}
else if (timeSpan.Minutes != 0)
{
return string.Format("{0:D2}min", timeSpan.Minutes);
}
else
{
return string.Format("{0:D2}s", timeSpan.Seconds);
}
}
<phone:PhoneApplicationPage
x:Class="Blog_Itineraire.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True" xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls" xmlns:my="clr-namespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Controls.Maps" xmlns:my1="clr-namespace:System.Device.Location;assembly=System.Device">
<!--LayoutRoot est la grille racine où tout le contenu de la page est placé-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<controls:Pivot Height="768" HorizontalAlignment="Left" Name="MainPivot" Title="Rolandl Itinéraire" VerticalAlignment="Top" Width="480">
<controls:PivotItem Header="Ecran de saisie">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="70"/>
<RowDefinition Height="70"/>
<RowDefinition Height="70"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Margin="10,0,0,0" Text="Départ : " VerticalAlignment="Center" />
<TextBox Grid.Row="0" Grid.Column="1" Width="360" Name="txtDepart" />
<TextBlock Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" Margin="10,0,0,0" Text="Arrivée :" VerticalAlignment="Center" />
<TextBox Grid.Row="1" Grid.Column="1" Width="360" Name="txtArrivee" />
<Button Grid.Row="2" Grid.ColumnSpan="2" Name="btnRecherche" Content="Rechercher" Click="btnRecherche_Click" />
</Grid>
</controls:PivotItem>
<controls:PivotItem Header="Carte">
<Grid>
<my:Map HorizontalAlignment="Left" Name="mapItineraire" VerticalAlignment="Top" Width="455" Height="600" CopyrightVisibility="Collapsed" LogoVisibility="Collapsed" ZoomLevel="10" ZoomBarVisibility="Visible">
<my:Map.CredentialsProvider>
<my:ApplicationIdCredentialsProvider ApplicationId="Au..." />
</my:Map.CredentialsProvider>
<my:Map.Center>
<my1:GeoCoordinate Altitude="NaN" Course="NaN" HorizontalAccuracy="NaN" Latitude="47.64483" Longitude="-122.141197" Speed="NaN" VerticalAccuracy="NaN" />
</my:Map.Center>
</my:Map>
</Grid>
</controls:PivotItem>
<controls:PivotItem Header="Détails">
<StackPanel>
<TextBlock Name="lblDepart" />
<TextBlock Name="lblArrivee" />
<TextBlock Name="lblDistance" />
<TextBlock Name="lblTemps" />
<ListBox Name="lstBoxItineraire" Height="480" Margin="0,20,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Grid Width="440">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding temps}" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" />
<TextBlock Text="{Binding distance}" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Right" />
<TextBlock Text="{Binding instruction}" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" TextWrapping="Wrap" Margin="0,10,0,0" />
</Grid>
<Rectangle Fill="White" Height="1" Margin="0,10" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</controls:PivotItem>
</controls:Pivot>
</Grid>
<shell:SystemTray.ProgressIndicator>
<shell:ProgressIndicator IsIndeterminate="True" IsVisible="False" x:Name="progressIndicator" />
</shell:SystemTray.ProgressIndicator>
</phone:PhoneApplicationPage>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Blog_Itineraire.GeocodeService;
using Microsoft.Phone.Controls.Maps;
using Blog_Itineraire.RouteService;
using System.Collections.ObjectModel;
using Microsoft.Phone.Controls.Maps.Platform;
using System.Device.Location;
namespace Blog_Itineraire
{
public partial class MainPage : PhoneApplicationPage
{
private GeocodeServiceClient geocodeService;
private GeocodeRequest geocodeReq;
private GeocodeResult geocodeResDepart;
private GeocodeResult geocodeResArrivee;
private RouteServiceClient routeService;
private string query;
// Constructeur
public MainPage()
{
InitializeComponent();
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
//On instancie les services
geocodeService = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
geocodeService.GeocodeCompleted += geocodeService_GeocodeCompleted;
routeService = new RouteServiceClient("BasicHttpBinding_IRouteService");
//On instancie la requête
geocodeReq = new GeocodeRequest();
geocodeReq.Credentials = new Credentials() { ApplicationId = "Au..." };
}
private void btnRecherche_Click(object sender, RoutedEventArgs e)
{
if (txtDepart.Text == "")
{
MessageBox.Show("Merci de saisir un lieu de départ");
}
else if (txtArrivee.Text == "")
{
MessageBox.Show("Merci de saisir un lieu d'arrivée");
}
else
{
//On indique que l'application tourne
progressIndicator.IsVisible = true;
//On indique le type de la requête
query = "depart";
//On lance la recherche
geocodeReq.Query = txtDepart.Text;
geocodeService.GeocodeAsync(geocodeReq);
}
}
private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
if (e.Result != null && e.Result.Results.Any(x => x.Locations != null && x.Locations.Any()))
{
if (query == "depart")
{
//On récupère les coordonnées du point de départ
geocodeResDepart = e.Result.Results.FirstOrDefault();
//On indique le type de la nouvelle requête
query = "arrivee";
//On lance la recherche pour le point d'arrivée
geocodeReq.Query = txtArrivee.Text;
geocodeService.GeocodeAsync(geocodeReq);
}
else
{
//On récupère les coordonnées du point d'arrivée
geocodeResArrivee = e.Result.Results.FirstOrDefault();
//On lance l'itinéraire
calculItineraire();
}
}
else
{
if (query == "depart")
{
MessageBox.Show("Impossible de localiser le départ");
}
else
{
MessageBox.Show("Impossible de localiser l'arrivée");
}
}
}
private void calculItineraire()
{
//On instancie la requête
RouteRequest routeReq = new RouteRequest();
routeReq.Credentials = new Credentials() { ApplicationId = "Au..." };
//Points de départ et d'arrivée de l'itinéraire
Waypoint wayPointDepart = new Waypoint() { Location = new Location() { Longitude = geocodeResDepart.Locations.FirstOrDefault().Longitude, Latitude = geocodeResDepart.Locations.FirstOrDefault().Latitude }, Description = geocodeResDepart.DisplayName };
Waypoint wayPointArrivee = new Waypoint() { Location = new Location() { Longitude = geocodeResArrivee.Locations.FirstOrDefault().Longitude, Latitude = geocodeResArrivee.Locations.FirstOrDefault().Latitude }, Description = geocodeResArrivee.DisplayName };
//On précise les points les lequels on veut passer dans l'itinéraire
routeReq.Waypoints = new ObservableCollection<Waypoint>();
routeReq.Waypoints.Add(wayPointDepart);
routeReq.Waypoints.Add(wayPointArrivee);
//Quelques options...
routeReq.Options = new RouteOptions() { Mode = TravelMode.Driving, RoutePathType = RoutePathType.Points };
routeReq.Culture = "FR-fr";
//On détermine la méthode à appeler quand cla recherche est terminée
routeService.CalculateRouteCompleted += routeService_CalculateRouteCompleted;
//On lance la recherche
routeService.CalculateRouteAsync(routeReq);
}
private void routeService_CalculateRouteCompleted(object sender, CalculateRouteCompletedEventArgs e)
{
if (e.Result != null && e.Result.Result != null && e.Result.Result.Legs != null && e.Result.Result.Legs.Any())
{
//Pushpin pour marquer le début et la fin du trajet
Pushpin pinDepart = new Pushpin() { Location = new GeoCoordinate(geocodeResDepart.Locations.FirstOrDefault().Latitude, geocodeResDepart.Locations.FirstOrDefault().Longitude), Content = "Début" };
Pushpin pinArrivee = new Pushpin() { Location = new GeoCoordinate(geocodeResArrivee.Locations.FirstOrDefault().Latitude, geocodeResArrivee.Locations.FirstOrDefault().Longitude), Content = "Fin" };
//On fait le tracé
var locationLst = new LocationCollection();
foreach (Location loc in e.Result.Result.RoutePath.Points)
{
locationLst.Add(new GeoCoordinate(loc.Latitude, loc.Longitude));
}
MapPolyline polyline = new MapPolyline() { Stroke = new SolidColorBrush(Colors.Blue), StrokeThickness = 5, Locations = locationLst };
//On ajouter les pushpin et le tracé sur la carte
mapItineraire.Children.Add(pinArrivee);
mapItineraire.Children.Add(pinDepart);
mapItineraire.Children.Add(polyline);
//On centre la carte sur le départ
mapItineraire.SetView(pinDepart.Location, 10);
//On affiche le détail de l'itineraire
afficherItineraire(e.Result.Result.Legs.FirstOrDefault());
}
else
{
MessageBox.Show("Impossible de calculer l'itinéraire");
}
}
private void afficherItineraire(RouteLeg leg)
{
//Infos générales
lblDepart.Text = "Départ : " + geocodeResDepart.DisplayName;
lblArrivee.Text = "Arrivée : " + geocodeResArrivee.DisplayName;
lblDistance.Text = "Distance : " + leg.Summary.Distance + " km";
lblTemps.Text = "Temps : " + ConvertirTemps(leg.Summary.TimeInSeconds);
//Les étapes
List<ItineraireEtape> lstSteps = new List<ItineraireEtape>();
foreach (ItineraryItem item in leg.Itinerary)
{
lstSteps.Add(new ItineraireEtape() { temps = ConvertirTemps(item.Summary.TimeInSeconds), distance = item.Summary.Distance.ToString() + " km", instruction = ParseItineraire(item.Text) });
}
lstBoxItineraire.ItemsSource = lstSteps;
//On stoppe l'indicateur
progressIndicator.IsVisible = false;
}
private string ParseItineraire(string itemText)
{
//On enlève les morceaux de XML
itemText = itemText.Replace("<VirtualEarth:Action>", "");
itemText = itemText.Replace("</VirtualEarth:Action>", "");
itemText = itemText.Replace("<VirtualEarth:TurnDir>", "");
itemText = itemText.Replace("</VirtualEarth:TurnDir>", "");
itemText = itemText.Replace("<VirtualEarth:Toward>", "");
itemText = itemText.Replace("</VirtualEarth:Toward>", "");
itemText = itemText.Replace("<VirtualEarth:RoadName>", "");
itemText = itemText.Replace("</VirtualEarth:RoadName>", "");
itemText = itemText.Replace("<VirtualEarth:ExitNumber>", "");
itemText = itemText.Replace("</VirtualEarth:ExitNumber>", "");
itemText = itemText.Replace("<VirtualEarth:Sign>", "");
itemText = itemText.Replace("</VirtualEarth:Sign>", "");
itemText = itemText.Replace("<VirtualEarth:WaypointName>", "");
itemText = itemText.Replace("</VirtualEarth:WaypointName>", "");
return itemText;
}
private string ConvertirTemps(long timeInSeconds)
{
TimeSpan timeSpan = TimeSpan.FromSeconds(timeInSeconds);
if (timeSpan.Hours != 0)
{
return string.Format("{0:D2}h{1:D2}min", timeSpan.Hours, timeSpan.Minutes);
}
else if (timeSpan.Minutes != 0)
{
return string.Format("{0:D2}min", timeSpan.Minutes);
}
else
{
return string.Format("{0:D2}s", timeSpan.Seconds);
}
}
}
}
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace Blog_Itineraire
{
public class ItineraireEtape
{
public string temps { get; set; }
public string distance { get; set; }
public string instruction { get; set; }
}
}