Let There Be Code RSS 2.0
# Friday, July 13, 2012

Suite et fin de cette série d’articles… Après une 1ère partie sur l’utilisation du contrôle Map dans une application Metro, puis une 2ème partie sur la recherche de localités via les services REST Bing Maps et le Search Charm, nous allons maintenant intégrer le calcul d’itinéraire et l’affichage des incidents de circulation.

Commençons par le plus simple, l’affichage des incidents de circulation. Bing Maps met à disposition un service REST permettant de récupérer ce type d’information. Suivez ce lien pour une documentation complète du service d’incidents.

L’URL de base du service Bing Maps est la suivante : http://dev.virtualearth.net/REST/v1/Traffic/Incidents/

Il faut ensuite ajouter un paramètre représentant la zone géographique. Une zone géographique est représentée par un rectangle (Latitude Sud, Longitude Ouest, Latitude Nord, Longitude Est).

On peut également ajouter des paramètres supplémentaires optionnels afin de filtrer les résultats (severity : gravité des incidents, type : type d’incidents).

Pour l’intégration de ces informations dans notre application Bing Maps Metro, nous allons nous connecter à l’évènement ViewChangeEnded du contrôle Map :

  1. <Maps:Map x:Name="myMaps"
  2.           Credentials="Your Bing Maps Key"
  3.           MapType="Aerial"
  4.           ShowTraffic="True"
  5.           ShowScaleBar="False"
  6.           ZoomLevel="17"
  7.           ViewChangeEnded="myMaps_ViewChangeEnded"
  8.           >
  9.     <Maps:Map.Center>
  10.         <Maps:Location Latitude="48.830617" Longitude="2.261645" />
  11.     </Maps:Map.Center>
  12. </Maps:Map>

 

Pour ne pas surcharger la carte avec trop d’informations, nous n’afficherons les incidents que dans le cas où le niveau de zoom est supérieur à 10 et si l’option d’affichage du trafic est activée. A chaque modification de la vue (manipulation de la carte par l’utilisateur), nous supprimons tous les points d’intérêt représentant des incidents, pour ensuite ajouter les nouveaux :

  1. private List<Pushpin> incidentPushpins = new List<Pushpin>();
  2.  
  3. private async void myMaps_ViewChangeEnded(object sender, ViewChangeEndedEventArgs e)
  4. {
  5.     if (myMaps.ZoomLevel > 10 && myMaps.ShowTraffic == true)
  6.     {
  7.         foreach (var item in incidentPushpins)
  8.         {
  9.             if (myMaps.Children.Contains(item))
  10.                 myMaps.Children.Remove(item);
  11.         }
  12.         incidentPushpins.Clear();
  13.  
  14.         ...
  15.     }
  16. }

 

La zone géographique représentant le paramètre mapArea du service REST Bing Maps peut être composée de cette manière en utilisant la propriété TargetBounds du contrôle Map :

  1. string mapArea = myMaps.TargetBounds.South + "," + myMaps.TargetBounds.West + "," + myMaps.TargetBounds.North + "," + myMaps.TargetBounds.East;

 

L’URL pour interroger le service de récupération des incidents de circulation est la suivante :

  1. string uri = "http://dev.virtualearth.net/REST/v1/Traffic/Incidents/" + mapArea + "?key=" + BingMapsKey;

 

Il nous faut maintenant instancier un objet HttpClient afin d’envoyer notre requête et de récupérer le résultat :

  1. HttpClient client = new HttpClient();
  2. var result = await client.GetStringAsync(uri);

 

Le résultat est un flux Json contenant la liste des incidents dans la zone demandée :

  1: {
  2:     "authenticationResultCode": "ValidCredentials",
  3:     "brandLogoUri": "http://dev.virtualearth.net/Branding/logo_powered_by.png",
  4:     "copyright": "Copyright © 2012 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
  5:     "resourceSets": [
  6:         {
  7:             "estimatedTotal": 2,
  8:             "resources": [
  9:                 {
 10:                     "__type": "TrafficIncident:http://schemas.microsoft.com/search/local/ws/rest/v1",
 11:                     "point": {
 12:                         "type": "Point",
 13:                         "coordinates": [
 14:                             48.81982,
 15:                             2.32425
 16:                         ]
 17:                     },
 18:                     "description": "entre Porte d'Orléans (E2) et Porte de Gentilly - Fermé.",
 19:                     "end": "/Date(1342258789000)/",
 20:                     "incidentId": 323566599,
 21:                     "lastModified": "/Date(1342085989000)/",
 22:                     "roadClosed": true,
 23:                     "severity": 4,
 24:                     "start": "/Date(1342085940000)/",
 25:                     "toPoint": {
 26:                         "type": "Point",
 27:                         "coordinates": [
 28:                             48.81912,
 29:                             2.34364
 30:                         ]
 31:                     },
 32:                     "type": 8,
 33:                     "verified": true
 34:                 },
 35:                 {
 36:                     "__type": "TrafficIncident:http://schemas.microsoft.com/search/local/ws/rest/v1",
 37:                     "point": {
 38:                         "type": "Point",
 39:                         "coordinates": [
 40:                             48.81982,
 41:                             2.32425
 42:                         ]
 43:                     },
 44:                     "description": "entre Porte d'Orléans (E2) et Porte de Gentilly - Travaux sur tronçon.",
 45:                     "end": "/Date(1342389600000)/",
 46:                     "incidentId": 322895570,
 47:                     "lastModified": "/Date(1341847492000)/",
 48:                     "roadClosed": false,
 49:                     "severity": 2,
 50:                     "start": "/Date(1341847260000)/",
 51:                     "toPoint": {
 52:                         "type": "Point",
 53:                         "coordinates": [
 54:                             48.81912,
 55:                             2.34364
 56:                         ]
 57:                     },
 58:                     "type": 9,
 59:                     "verified": true
 60:                 }
 61:             ]
 62:         }
 63:     ],
 64:     "statusCode": 200,
 65:     "statusDescription": "OK",
 66:     "traceId": "468e0ef9b5694d3e81d26623bbf5a3fe|AMSM001106|02.00.138.500|"
 67: }

Dans ce flux, nous devons récupérer et parcourir le tableau resources :

  1. var values = JsonValue.Parse(result);
  2.  
  3. var incidents = values.GetObject()["resourceSets"].GetArray()[0].GetObject()["resources"].GetArray();
  4.  
  5. foreach (var item in incidents)
  6. {
  7.     ...
  8. }

 

Pour chacun des incidents, récupérer sa description et ses coordonnées :

  1. var description = item.GetObject()["description"].GetString();
  2. var coordinates = item.GetObject()["point"].GetObject()["coordinates"].GetArray();

 

Et pour terminer, créer un objet de type Pushpin, le positionner et l’ajouter à la carte, puis ajouter un tooltip :

  1. Location location = new Location(coordinates[0].GetNumber(), coordinates[1].GetNumber());
  2.  
  3. Pushpin pushpin = new Pushpin() { Text = "" };
  4. MapLayer.SetPosition(pushpin, location);
  5. myMaps.Children.Add(pushpin);
  6.  
  7. ToolTipService.SetToolTip(pushpin, description);
  8. incidentPushpins.Add(pushpin);

 

Et voilà le résultat :

BingMaps1

 

Pour mieux identifier ces points d’intérêt comme étant des incidents, il est possible de personnaliser le style des contrôles Pushpin.

Nous allons ajouter cette image BingMaps3dans notre solution :

BingMaps2

 

Ensuite dans les ressources de la page MainPage nous ajoutons le ControlTemplate suivant :

  1. <ControlTemplate x:Key="IncidentPushpin" TargetType="Maps:Pushpin">
  2.     <Image Source="Images/incident.png" Stretch="None" HorizontalAlignment="Left" />
  3. </ControlTemplate>

 

Il nous faut maintenant appliquer ce template lorsque l’on crée les objets de type Pushpin :

  1. Pushpin pushpin = new Pushpin() { Text = "" };
  2. pushpin.Template = Resources["IncidentPushpin"] as ControlTemplate;

 

Voici le code complet de la méthode myMaps_ViewChangeEnded :

  1. private async void myMaps_ViewChangeEnded(object sender, ViewChangeEndedEventArgs e)
  2. {
  3.     if (myMaps.ZoomLevel > 10 && myMaps.ShowTraffic == true)
  4.     {
  5.         foreach (var item in incidentPushpins)
  6.         {
  7.             if (myMaps.Children.Contains(item))
  8.                 myMaps.Children.Remove(item);
  9.         }
  10.         incidentPushpins.Clear();
  11.  
  12.         string mapArea = myMaps.TargetBounds.South + "," + myMaps.TargetBounds.West + "," + myMaps.TargetBounds.North + "," + myMaps.TargetBounds.East;
  13.         string uri = "http://dev.virtualearth.net/REST/v1/Traffic/Incidents/" + mapArea + "?key=" + BingMapsKey;
  14.  
  15.         JsonValue values = null;
  16.         try
  17.         {
  18.             HttpClient client = new HttpClient();
  19.             var result = await client.GetStringAsync(uri);
  20.  
  21.             values = JsonValue.Parse(result);
  22.         }
  23.         catch
  24.         {
  25.             MessageDialog dialog = new MessageDialog("Unable to find traffic incidents...");
  26.             dialog.ShowAsync();
  27.             return;
  28.         }
  29.  
  30.         if (values == null)
  31.             return;
  32.  
  33.         var incidents = values.GetObject()["resourceSets"].GetArray()[0].GetObject()["resources"].GetArray();
  34.  
  35.         foreach (var item in incidents)
  36.         {
  37.             var description = item.GetObject()["description"].GetString();
  38.             var coordinates = item.GetObject()["point"].GetObject()["coordinates"].GetArray();
  39.  
  40.             Location location = new Location(coordinates[0].GetNumber(), coordinates[1].GetNumber());
  41.  
  42.             Pushpin pushpin = new Pushpin() { Text = "" };
  43.             pushpin.Template = Resources["IncidentPushpin"] as ControlTemplate;
  44.  
  45.             MapLayer.SetPosition(pushpin, location);
  46.             myMaps.Children.Add(pushpin);
  47.  
  48.             ToolTipService.SetToolTip(pushpin, description);
  49.             incidentPushpins.Add(pushpin);
  50.         }
  51.  
  52.     }
  53. }

 

Et le résultat en image :

BingMaps4

 

Nous allons maintenant développer la dernière fonctionnalité, qui est d’intégrer le calcul d’itinéraire. Pour consulter la documentation complète de l’API Routes des services Bing Maps, suivez ce lien.

L’URI de base pour calculer un itinéraire via les services Bing Maps est la suivante : http://dev.virtualearth.net/REST/v1/Routes/

Il faut ensuite ajouter des paramètres de type waypoint.n pour indiquer les différents points de passage. Un point de passage (début, intermédiaire, fin) est représenté soit par des coordonnées géographiques ou un requête (par exemple, une adresse).

Voici ici une URI qui nous permet de rechercher un itinéraire pour aller de Toulouse à Paris : http://dev.virtualearth.net/REST/V1/Routes/Driving?wp.0=toulouse&wp.1=paris&avoid=minimizeTolls&routePathOutput=points&key=XXXXXXXXXXXX

On remarque dans cette URI, le paramètre Driving. Ce paramètre permet d’indiquer le type de déplacement souhaité et peut prendre comme valeur driving, walking ou transit.

Le paramètre avoid permet d’indiquer comment nous voulons optimiser l’itinéraire. La valeur minimizeTolls indique d’éviter les péages autant que possible.

Et le paramètre routePathOutput permet d’indiquer si l’on veut la liste des points représentant le chemin de l’itinéraire (valeur points ou none).

Voici le format de la réponse Json :

  1: {
  2:     "authenticationResultCode": "ValidCredentials",
  3:     "brandLogoUri": "http://dev.virtualearth.net/Branding/logo_powered_by.png",
  4:     "copyright": "Copyright © 2012 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
  5:     "resourceSets": [
  6:         {
  7:             "estimatedTotal": 1,
  8:             "resources": [
  9:                 {
 10:                     "__type": "Route:http://schemas.microsoft.com/search/local/ws/rest/v1",
 11:                     "bbox": [
 12:                         43.61451,
 13:                         1.463354,
 14:                         43.617219,
 15:                         1.465543
 16:                     ],
 17:                     "id": "v63,i0,a2,cen-US,dAAAAAAAAAAA=,y0,s1,m1,o1,t4,wtYbgA6hMIQA=~A1rKBEkRzUwuAADgAaxvKz8A~QXZlbnVlIGR1IENvbW1hbmRhbnQgVGFpbGxhbmRpZXIsIDMxNTAwIFRvdWxvdXNl~~~,wQ3ngA/VPIQA=~A1rKBEkhH04uAADgAQAAgD8A~QXZlbnVlIEzDqW9uIEJsdW0sIDMxNTAwIFRvdWxvdXNl~~~,k1,u",
 18:                     "distanceUnit": "Kilometer",
 19:                     "durationUnit": "Second",
 20:                     "routeLegs": [
 21:                         {
 22:                             "actualEnd": {
 23:                                 "type": "Point",
 24:                                 "coordinates": [
 25:                                     43.614548,
 26:                                     1.46396
 27:                                 ]
 28:                             },
 29:                             "actualStart": {
 30:                                 "type": "Point",
 31:                                 "coordinates": [
 32:                                     43.616874,
 33:                                     1.463354
 34:                                 ]
 35:                             },
 36:                             "endLocation": {
 37:                                 "bbox": [
 38:                                     43.610703,
 39:                                     1.456808,
 40:                                     43.618429,
 41:                                     1.471034
 42:                                 ],
 43:                                 "name": "Avenue Léon Blum, 31500 Toulouse",
 44:                                 "point": {
 45:                                     "type": "Point",
 46:                                     "coordinates": [
 47:                                         43.614566,
 48:                                         1.463921
 49:                                     ]
 50:                                 },
 51:                                 "address": {
 52:                                     "addressLine": "Avenue Léon Blum",
 53:                                     "adminDistrict": "Midi-Pyrénées",
 54:                                     "adminDistrict2": "Haute-Garonne",
 55:                                     "countryRegion": "France",
 56:                                     "formattedAddress": "Avenue Léon Blum, 31500 Toulouse",
 57:                                     "locality": "Toulouse",
 58:                                     "postalCode": "31500"
 59:                                 },
 60:                                 "confidence": "High",
 61:                                 "entityType": "RoadBlock",
 62:                                 "geocodePoints": [
 63:                                     {
 64:                                         "type": "Point",
 65:                                         "coordinates": [
 66:                                             43.614566,
 67:                                             1.463921
 68:                                         ],
 69:                                         "calculationMethod": "Interpolation",
 70:                                         "usageTypes": [
 71:                                             "Display",
 72:                                             "Route"
 73:                                         ]
 74:                                     }
 75:                                 ],
 76:                                 "matchCodes": [
 77:                                     "Good"
 78:                                 ]
 79:                             },
 80:                             "itineraryItems": [
 81:                                 {
 82:                                     "compassDirection": "southeast",
 83:                                     "details": [
 84:                                         {
 85:                                             "compassDegrees": 114,
 86:                                             "endPathIndices": [
 87:                                                 1
 88:                                             ],
 89:                                             "maneuverType": "DepartStart",
 90:                                             "mode": "Driving",
 91:                                             "names": [
 92:                                                 "Avenue du Commandant Taillandier"
 93:                                             ],
 94:                                             "roadType": "Street",
 95:                                             "startPathIndices": [
 96:                                                 0
 97:                                             ]
 98:                                         }
 99:                                     ],
100:                                     "exit": "",
101:                                     "iconType": "Auto",
102:                                     "instruction": {
103:                                         "maneuverType": "DepartStart",
104:                                         "text": "Depart Avenue du Commandant Taillandier toward Rue Benjamin Baillaud"
105:                                     },
106:                                     "maneuverPoint": {
107:                                         "type": "Point",
108:                                         "coordinates": [
109:                                             43.616874,
110:                                             1.463354
111:                                         ]
112:                                     },
113:                                     "sideOfStreet": "Unknown",
114:                                     "tollZone": "",
115:                                     "towardsRoadName": "Rue Benjamin Baillaud",
116:                                     "transitTerminus": "",
117:                                     "travelDistance": 0.078,
118:                                     "travelDuration": 8,
119:                                     "travelMode": "Driving"
120:                                 },
121:                                 {
122:                                     "compassDirection": "northeast",
123:                                     "details": [
124:                                         {
125:                                             "compassDegrees": 53,
126:                                             "endPathIndices": [
127:                                                 5
128:                                             ],
129:                                             "maneuverType": "TurnLeft",
130:                                             "mode": "Driving",
131:                                             "names": [
132:                                                 "Rue Benjamin Baillaud"
133:                                             ],
134:                                             "roadType": "Street",
135:                                             "startPathIndices": [
136:                                                 1
137:                                             ]
138:                                         }
139:                                     ],
140:                                     "exit": "",
141:                                     "iconType": "Auto",
142:                                     "instruction": {
143:                                         "maneuverType": "TurnLeft",
144:                                         "text": "Turn left onto Rue Benjamin Baillaud"
145:                                     },
146:                                     "maneuverPoint": {
147:                                         "type": "Point",
148:                                         "coordinates": [
149:                                             43.6165,
150:                                             1.464191
151:                                         ]
152:                                     },
153:                                     "sideOfStreet": "Unknown",
154:                                     "tollZone": "",
155:                                     "transitTerminus": "",
156:                                     "travelDistance": 0.142,
157:                                     "travelDuration": 30,
158:                                     "travelMode": "Driving"
159:                                 },
160:                                 {
161:                                     "compassDirection": "southwest",
162:                                     "details": [
163:                                         {
164:                                             "compassDegrees": 214,
165:                                             "endPathIndices": [
166:                                                 8
167:                                             ],
168:                                             "maneuverType": "TurnRight",
169:                                             "mode": "Driving",
170:                                             "names": [
171:                                                 "Avenue Yves Brunaud"
172:                                             ],
173:                                             "roadType": "Highway",
174:                                             "startPathIndices": [
175:                                                 5
176:                                             ]
177:                                         }
178:                                     ],
179:                                     "exit": "",
180:                                     "iconType": "Auto",
181:                                     "instruction": {
182:                                         "maneuverType": "TurnRight",
183:                                         "text": "Turn right onto Avenue Yves Brunaud"
184:                                     },
185:                                     "maneuverPoint": {
186:                                         "type": "Point",
187:                                         "coordinates": [
188:                                             43.617128,
189:                                             1.4655
190:                                         ]
191:                                     },
192:                                     "sideOfStreet": "Unknown",
193:                                     "tollZone": "",
194:                                     "transitTerminus": "",
195:                                     "travelDistance": 0.17,
196:                                     "travelDuration": 33,
197:                                     "travelMode": "Driving"
198:                                 },
199:                                 {
200:                                     "compassDirection": "southeast",
201:                                     "details": [
202:                                         {
203:                                             "compassDegrees": 270,
204:                                             "endPathIndices": [
205:                                                 13
206:                                             ],
207:                                             "maneuverType": "EnterRoundabout",
208:                                             "mode": "Driving",
209:                                             "names": [
210:                                                 "Rond-point du Capitaine Alfred Dreyfus"
211:                                             ],
212:                                             "roadType": "Highway",
213:                                             "startPathIndices": [
214:                                                 8
215:                                             ]
216:                                         },
217:                                         {
218:                                             "compassDegrees": 143,
219:                                             "endPathIndices": [
220:                                                 15
221:                                             ],
222:                                             "maneuverType": "ExitRoundabout",
223:                                             "mode": "Driving",
224:                                             "names": [
225:                                                 "Boulevard des Crêtes"
226:                                             ],
227:                                             "roadType": "MajorRoad",
228:                                             "startPathIndices": [
229:                                                 13
230:                                             ]
231:                                         }
232:                                     ],
233:                                     "exit": "2",
234:                                     "iconType": "Auto",
235:                                     "instruction": {
236:                                         "maneuverType": "EnterThenExitRoundabout",
237:                                         "text": "At roundabout, take 2nd exit onto Boulevard des Crêtes"
238:                                     },
239:                                     "maneuverPoint": {
240:                                         "type": "Point",
241:                                         "coordinates": [
242:                                             43.615653,
243:                                             1.46506
244:                                         ]
245:                                     },
246:                                     "sideOfStreet": "Unknown",
247:                                     "tollZone": "",
248:                                     "transitTerminus": "",
249:                                     "travelDistance": 0.168,
250:                                     "travelDuration": 33,
251:                                     "travelMode": "Driving"
252:                                 },
253:                                 {
254:                                     "compassDirection": "west",
255:                                     "details": [
256:                                         {
257:                                             "compassDegrees": 272,
258:                                             "endPathIndices": [
259:                                                 17
260:                                             ],
261:                                             "maneuverType": "TurnRight",
262:                                             "mode": "Driving",
263:                                             "names": [
264:                                                 "Avenue Léon Blum"
265:                                             ],
266:                                             "roadType": "MajorRoad",
267:                                             "startPathIndices": [
268:                                                 15
269:                                             ]
270:                                         }
271:                                     ],
272:                                     "exit": "",
273:                                     "iconType": "Auto",
274:                                     "instruction": {
275:                                         "maneuverType": "TurnRight",
276:                                         "text": "Turn right onto Avenue Léon Blum"
277:                                     },
278:                                     "maneuverPoint": {
279:                                         "type": "Point",
280:                                         "coordinates": [
281:                                             43.614521,
282:                                             1.465543
283:                                         ]
284:                                     },
285:                                     "sideOfStreet": "Unknown",
286:                                     "tollZone": "",
287:                                     "transitTerminus": "",
288:                                     "travelDistance": 0.13,
289:                                     "travelDuration": 28,
290:                                     "travelMode": "Driving"
291:                                 },
292:                                 {
293:                                     "compassDirection": "west",
294:                                     "details": [
295:                                         {
296:                                             "compassDegrees": 272,
297:                                             "endPathIndices": [
298:                                                 17
299:                                             ],
300:                                             "maneuverType": "ArriveFinish",
301:                                             "mode": "Driving",
302:                                             "names": [
303:                                                 "Avenue Léon Blum"
304:                                             ],
305:                                             "roadType": "MajorRoad",
306:                                             "startPathIndices": [
307:                                                 17
308:                                             ]
309:                                         }
310:                                     ],
311:                                     "exit": "",
312:                                     "hints": [
313:                                         {
314:                                             "hintType": null,
315:                                             "text": "The last intersection is Boulevard des Crêtes"
316:                                         },
317:                                         {
318:                                             "hintType": null,
319:                                             "text": "If you reach Avenue Yves Brunaud, you've gone too far"
320:                                         }
321:                                     ],
322:                                     "iconType": "Auto",
323:                                     "instruction": {
324:                                         "maneuverType": "ArriveFinish",
325:                                         "text": "Arrive at Avenue Léon Blum, 31500 Toulouse"
326:                                     },
327:                                     "maneuverPoint": {
328:                                         "type": "Point",
329:                                         "coordinates": [
330:                                             43.614548,
331:                                             1.46396
332:                                         ]
333:                                     },
334:                                     "sideOfStreet": "Unknown",
335:                                     "tollZone": "",
336:                                     "transitTerminus": "",
337:                                     "travelDistance": 0,
338:                                     "travelDuration": 0,
339:                                     "travelMode": "Driving"
340:                                 }
341:                             ],
342:                             "startLocation": {
343:                                 "bbox": [
344:                                     43.613011,
345:                                     1.45624,
346:                                     43.620737,
347:                                     1.470468
348:                                 ],
349:                                 "name": "Avenue du Commandant Taillandier, 31500 Toulouse",
350:                                 "point": {
351:                                     "type": "Point",
352:                                     "coordinates": [
353:                                         43.616874,
354:                                         1.463354
355:                                     ]
356:                                 },
357:                                 "address": {
358:                                     "addressLine": "Avenue du Commandant Taillandier",
359:                                     "adminDistrict": "Midi-Pyrénées",
360:                                     "adminDistrict2": "Haute-Garonne",
361:                                     "countryRegion": "France",
362:                                     "formattedAddress": "Avenue du Commandant Taillandier, 31500 Toulouse",
363:                                     "locality": "Toulouse",
364:                                     "postalCode": "31500"
365:                                 },
366:                                 "confidence": "High",
367:                                 "entityType": "RoadBlock",
368:                                 "geocodePoints": [
369:                                     {
370:                                         "type": "Point",
371:                                         "coordinates": [
372:                                             43.616874,
373:                                             1.463354
374:                                         ],
375:                                         "calculationMethod": "Interpolation",
376:                                         "usageTypes": [
377:                                             "Display",
378:                                             "Route"
379:                                         ]
380:                                     }
381:                                 ],
382:                                 "matchCodes": [
383:                                     "Good"
384:                                 ]
385:                             },
386:                             "travelDistance": 0.688,
387:                             "travelDuration": 133
388:                         }
389:                     ],
390:                     "routePath": {
391:                         "generalizations": [],
392:                         "line": {
393:                             "type": "LineString",
394:                             "coordinates": [
395:                                 [
396:                                     43.616873,
397:                                     1.463354
398:                                 ],
399:                                 [
400:                                     43.6165,
401:                                     1.464191
402:                                 ],
403:                                 [
404:                                     43.617171,
405:                                     1.465092
406:                                 ],
407:                                 [
408:                                     43.617219,
409:                                     1.465162
410:                                 ],
411:                                 [
412:                                     43.617197,
413:                                     1.465269
414:                                 ],
415:                                 [
416:                                     43.617128,
417:                                     1.465499
418:                                 ],
419:                                 [
420:                                     43.61701,
421:                                     1.465419
422:                                 ],
423:                                 [
424:                                     43.616462,
425:                                     1.46521
426:                                 ],
427:                                 [
428:                                     43.615652,
429:                                     1.46506
430:                                 ],
431:                                 [
432:                                     43.615652,
433:                                     1.464968
434:                                 ],
435:                                 [
436:                                     43.61562,
437:                                     1.464877
438:                                 ],
439:                                 [
440:                                     43.61547,
441:                                     1.46484
442:                                 ],
443:                                 [
444:                                     43.6154,
445:                                     1.464942
446:                                 ],
447:                                 [
448:                                     43.615438,
449:                                     1.465129
450:                                 ],
451:                                 [
452:                                     43.615379,
453:                                     1.465172
454:                                 ],
455:                                 [
456:                                     43.614521,
457:                                     1.465542
458:                                 ],
459:                                 [
460:                                     43.61451,
461:                                     1.46543
462:                                 ],
463:                                 [
464:                                     43.614547,
465:                                     1.46396
466:                                 ]
467:                             ]
468:                         }
469:                     },
470:                     "travelDistance": 0.688,
471:                     "travelDuration": 133
472:                 }
473:             ]
474:         }
475:     ],
476:     "statusCode": 200,
477:     "statusDescription": "OK",
478:     "traceId": "74808b399c51451dab1758f61ddd1c04|AMSM002207|02.00.138.500|AMSMSNVM002460, AMSMSNVM001314, AMSMSNVM001313, AMSMSNVM001322, AMSMSNVM002154, AMSMSNVM001307, AMSMSNVM002153, AMSMSNVM002408, AMSMSNVM001859, AMSMSNVM001857, AMSMSNVM001321, AMSMSNVM001863"
479: }

Dans ce flux Json nous avons l’objet bbox qui va nous permettre de centrer la carte sur la zone géographique de l’itinéraire via la méthode SetView :

  1. var values = JsonValue.Parse(result);
  2.  
  3. // bbox represents the Bounding box of route : SouthLatitude, WestLongitude, NorthLatitude, and EastLongitude
  4. var bbox = values.GetObject()["resourceSets"].GetArray()[0]
  5.                  .GetObject()["resources"].GetArray()[0]
  6.                  .GetObject()["bbox"].GetArray();
  7.  
  8. var southLat = bbox[0].GetNumber();
  9. var westLong = bbox[1].GetNumber();
  10. var northLat = bbox[2].GetNumber();
  11. var eastLong = bbox[3].GetNumber();
  12.  
  13. // center map on boundingbox of route
  14. var rect = new LocationRect(new Location(northLat, westLong), new Location(southLat, eastLong));
  15. CurrentMap.SetView(rect);

 

Dans le flux Json nous retrouvons également les valeurs travelDistance et travelDuration, ainsi que distanceUnit et durationUnit. Nous avons ici accès aux informations de temps de parcours et de la distance totale.

Ensuite 2 objets nous intéresse particulièrement dans le cadre de notre recherche d’itinéraire. Tout d’abord l’objet routePath, qui lui même contient un objet line avec les coordonnées de notre parcours :

  1. var coordinates = values.GetObject()["resourceSets"].GetArray()[0]
  2.                       .GetObject()["resources"].GetArray()[0]
  3.                       .GetObject()["routePath"]
  4.                       .GetObject()["line"]
  5.                       .GetObject()["coordinates"].GetArray();

 

Avec ces coordonnées nous allons pouvoir construire un objet MapPolyline pour représenter le parcours sur la carte. Un objet MapPolyline est composé d’un objet LocationCollection, d’une couleur et d’une taille :

  1. var locationCollection = new LocationCollection();
  2.  
  3. foreach (var coordinate in coordinates)
  4. {
  5.     var latitude = coordinate.GetArray()[0].GetNumber();
  6.     var longitude = coordinate.GetArray()[1].GetNumber();
  7.  
  8.     var location = new Bing.Maps.Location(latitude, longitude);
  9.     locationCollection.Add(location);
  10. }
  11.  
  12. MapPolyline polyline = new MapPolyline();
  13. polyline.Locations = locationCollection;
  14. polyline.Color = Windows.UI.Colors.Blue;
  15. polyline.Width = 5;

Ce type d’objet doit être ajouté à la carte par l’intermédiaire d’un layer de type MapShapeLayer :

  1. MapShapeLayer shapeLayer = new MapShapeLayer();
  2. shapeLayer.Shapes.Add(polyline);
  3. CurrentMap.ShapeLayers.Add(shapeLayer);

 

Voici le résultat que l’on obtient après ajout de l’objet MapPolyline :

BingMaps5

 

Il nous reste à positionner les différentes étapes de l’itinéraire.

Dans le flux Json nous retrouvons la liste de ces étapes au niveau du tableau itineraryItems :

  1. var itineraryItems = values.GetObject()["resourceSets"].GetArray()[0]
  2.                       .GetObject()["resources"].GetArray()[0]
  3.                       .GetObject()["routeLegs"].GetArray()[0]
  4.                       .GetObject()["itineraryItems"].GetArray();

Dans une étape d’itinéraire, nous récupérons les coordonnées du point de manœuvre et les instructions. Nous utilisons un incrément afin de représenter le numéro de l’étape sur l’objet Pushpin :

  1. int stepCounter = 1;
  2. foreach (var item in itineraryItems)
  3. {
  4.     var step = item.GetObject()["instruction"].GetObject()["text"].GetString();
  5.  
  6.     var point = item.GetObject()["maneuverPoint"].GetObject()["coordinates"].GetArray();
  7.  
  8.     var latitude = point[0].GetNumber();
  9.     var longitude = point[1].GetNumber();
  10.  
  11.     var location = new Location(latitude, longitude);
  12.     Pushpin pushpin = new Pushpin() { Text = stepCounter.ToString() };
  13.  
  14.     MapLayer.SetPosition(pushpin, location);
  15.     CurrentMap.Children.Add(pushpin);
  16.  
  17.     ToolTipService.SetToolTip(pushpin, step);
  18. }

 

Et voici le résultat :

BingMaps6

 

On peut ensuite mettre en place un UserControl qui va nous permettre de saisir les adresses de départ, de destination et afficher les instructions dans une ListView :

BingMaps7

 

L’archive suivante contient la solution complète au format VS 2012 RC :

Dans cette archive vous retrouverez les exemples décrits dans les 3 articles.

Il vous faudra éditer le fichier App.xaml afin de renseigner le paramètre BingMapsKey avec votre propre clé :

  1. <x:String x:Key="BingMapsKey">Your Bing Maps Key</x:String>
Friday, July 13, 2012 11:53:06 AM (Romance Daylight Time, UTC+02:00)  #    Voir Commentaires
BingMaps | Windows 8
# Wednesday, July 04, 2012

Cet article fait suite à une 1ère partie dans laquelle nous avons mis en place une application Metro intégrant une carte Bing Maps.

Dans cette 2ème partie je vous propose de découvrir comment utiliser les services REST de Bing Maps afin d’intégrer des fonctionnalités de recherche de localités. Afin d’être “Metro Compliant” nous nous intègrerons au Search Charm de Windows 8.

Pour une documentation complète des services REST Bing Maps je vous invite à consulter la documentation en ligne sur MSDN.

Pour retrouver la position d’un lieu, Bing Maps met à disposition plusieurs services web : recherche par adresse, par requête, par point.

1 premier web service permet de retrouver une localisation à partir d’une adresse. Nous devons donc fournir à ce web service des paramètres tels que le pays, le code postal, la ville ou encore la rue. Voici un exemple d’URL permettant de retrouver la place du capitole à Toulouse : http://dev.virtualearth.net/REST/v1/Locations/FR/31000/toulouse/place%20du%20capitole?maxResults=5&key=XXXXXXXXX

Notez le paramètre key : vous devez indiquer ici la clé d’accès aux services Bing Maps, que vous vous êtes créés depuis le portail.

Voici la réponse à cette requête au format json :

  1: {
  2:     "authenticationResultCode": "ValidCredentials",
  3:     "brandLogoUri": "http://dev.virtualearth.net/Branding/logo_powered_by.png",
  4:     "copyright": "Copyright © 2012 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
  5:     "resourceSets": [
  6:         {
  7:             "estimatedTotal": 1,
  8:             "resources": [
  9:                 {
 10:                     "__type": "Location:http://schemas.microsoft.com/search/local/ws/rest/v1",
 11:                     "bbox": [
 12:                         43.60056228242932,
 13:                         1.4366889613939073,
 14:                         43.608287717570676,
 15:                         1.4509130386060924
 16:                     ],
 17:                     "name": "Place du Capitole, 31000 Toulouse",
 18:                     "point": {
 19:                         "type": "Point",
 20:                         "coordinates": [
 21:                             43.604425,
 22:                             1.443801
 23:                         ]
 24:                     },
 25:                     "address": {
 26:                         "addressLine": "Place du Capitole",
 27:                         "adminDistrict": "Midi-Pyrénées",
 28:                         "adminDistrict2": "Haute-Garonne",
 29:                         "countryRegion": "France",
 30:                         "formattedAddress": "Place du Capitole, 31000 Toulouse",
 31:                         "locality": "Toulouse",
 32:                         "postalCode": "31000"
 33:                     },
 34:                     "confidence": "High",
 35:                     "entityType": "RoadBlock",
 36:                     "geocodePoints": [
 37:                         {
 38:                             "type": "Point",
 39:                             "coordinates": [
 40:                                 43.604425,
 41:                                 1.443801
 42:                             ],
 43:                             "calculationMethod": "Interpolation",
 44:                             "usageTypes": [
 45:                                 "Display",
 46:                                 "Route"
 47:                             ]
 48:                         }
 49:                     ],
 50:                     "matchCodes": [
 51:                         "Good"
 52:                     ]
 53:                 }
 54:             ]
 55:         }
 56:     ],
 57:     "statusCode": 200,
 58:     "statusDescription": "OK",
 59:     "traceId": "985f20b23f014beb91b6fda5ee2c4c46|BL2M002306|02.00.138.500|BL2MSNVM001813, BL2MSNVM001263"
 60: }

Ici la requête a renvoyé un seul résultat, dans lequel nous retrouvons un objet de type Point avec les coordonnées (43.604425, 1.443801).

Un petit coup de Bing Maps pour vérifier l’exactitude de ces coordonnées…

bingmaps1

 

Pour consulter la documentation détaillée de ce service de localisation par adresse, suivez ce lien.

Le second service de recherche de localisation se fait par requête. Une requête est tout simplement un champ texte que l’on soumet au service pour qu’il nous retourne les résultats correspondants. On peut par exemple effectuer la recherche d’un monument (ex: “Tour Eiffel”) ou encore d’une adresse (ex: “place du capitole, toulouse”).

En voici un exemple : http://dev.virtualearth.net/REST/v1/Locations?query=place%20du%20capitole%20toulouse&maxResults=5&key=XXXXXXXXX

Nous allons utiliser ce dernier service dans notre application et nous intégrer dans le charm de recherche de Windows 8 afin d’obtenir le résultat ci-dessous :

bingmaps2

 

Pour implémenter le charm de recherche, nous devons tout d’abord le déclarer au niveau du Manifest de l’application. Double-cliquez sur le fichier Package.appxmanifest, puis cliquez sur l’onglet Declarations. Dans la liste “Available Declarations” sélectionnez Search puis cliquez sur Add :

bingmaps3

 

Notre application est composée d’une unique page, MainPage, contenant la carte Bing Maps. C’est donc cette page qui traitera les recherches qu’effectue l’utilisateur.

Dans la classe MainPage, ajoutez une méthode SearchLocation qui prend en paramètre la requête de l’utilisateur :

  1. private async void SearchLocation(string query)
  2. {
  3.  
  4. }

 

Pour interroger le service REST Bing Maps nous allons utiliser un client HTTP, via la classe HttpClient de l’espace de nom System.Net.Http. Cette classe possède une méthode GetStringAsync, prenant en paramètre une Uri et renvoyant une chaine de caractère représentant la réponse :

  1. string uri = "http://dev.virtualearth.net/REST/v1/Locations/" + query + "?maxResults=1&key=XXXXXXXXXXXXX";
  2.  
  3. var client = new HttpClient();
  4. var result = await client.GetStringAsync(uri);

 

Dans notre variable result nous avons un flux json sous cette forme :

  1: {
  2:     "authenticationResultCode": "ValidCredentials",
  3:     "brandLogoUri": "http://dev.virtualearth.net/Branding/logo_powered_by.png",
  4:     "copyright": "Copyright © 2012 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
  5:     "resourceSets": [
  6:         {
  7:             "estimatedTotal": 1,
  8:             "resources": [
  9:                 {
 10:                     "__type": "Location:http://schemas.microsoft.com/search/local/ws/rest/v1",
 11:                     "bbox": [
 12:                         43.60056228242932,
 13:                         1.4366889613939073,
 14:                         43.608287717570676,
 15:                         1.4509130386060924
 16:                     ],
 17:                     "name": "Place du Capitole, 31000 Toulouse",
 18:                     "point": {
 19:                         "type": "Point",
 20:                         "coordinates": [
 21:                             43.604425,
 22:                             1.443801
 23:                         ]
 24:                     },
 25:                     "address": {
 26:                         "addressLine": "Place du Capitole",
 27:                         "adminDistrict": "Midi-Pyrénées",
 28:                         "adminDistrict2": "Haute-Garonne",
 29:                         "countryRegion": "France",
 30:                         "formattedAddress": "Place du Capitole, 31000 Toulouse",
 31:                         "locality": "Toulouse",
 32:                         "postalCode": "31000"
 33:                     },
 34:                     "confidence": "High",
 35:                     "entityType": "RoadBlock",
 36:                     "geocodePoints": [
 37:                         {
 38:                             "type": "Point",
 39:                             "coordinates": [
 40:                                 43.604425,
 41:                                 1.443801
 42:                             ],
 43:                             "calculationMethod": "Interpolation",
 44:                             "usageTypes": [
 45:                                 "Display",
 46:                                 "Route"
 47:                             ]
 48:                         }
 49:                     ],
 50:                     "matchCodes": [
 51:                         "Good"
 52:                     ]
 53:                 }
 54:             ]
 55:         }
 56:     ],
 57:     "statusCode": 200,
 58:     "statusDescription": "OK",
 59:     "traceId": "4558270dcc9949f0a5790553ede6281c|BL2M002301|02.00.138.500|BL2MSNVM002816, BL2MSNVM002809, BL2MSNVM003152, BL2MSNVM003206, BL2MSNVM001262"
 60: }

 

Pour parcourir ce flux Json, nous pouvons utiliser les classes de l’espace de nom Windows.Data.Json, et notamment la classe JsonValue qui possède une méthode Parse :

  1. JsonValue value = Windows.Data.Json.JsonValue.Parse(result);

 

Une fois que nous avons notre objet JsonValue, il nous faut le parcourir pour récupérer le nom et les coordonnées des différents résultats de localisation. L’analyse du flux json présenté ci-dessus, nous permet d’en déduire le code suivant :

  1. var resources = value.GetObject()["resourceSets"].GetArray()[0].GetObject()["resources"].GetArray();
  2.  
  3. foreach (var item in resources)
  4. {
  5.     var name = item.GetObject()["name"].GetString();
  6.  
  7.     var coordinates = item.GetObject()["point"].GetObject()["coordinates"].GetArray();
  8.  
  9.     var latitude = coordinates[0].GetNumber();
  10.     var longitude = coordinates[1].GetNumber();
  11.     
  12. }

 

Il ne reste plus qu’à créer un objet de type Location, l’objet Pushpin associé, de l’ajouter à la carte et de le positionner :

  1. var location = new Bing.Maps.Location(latitude, longitude);
  2.  
  3. Pushpin pushpin = new Pushpin() { Text = "!" };
  4. MapLayer.SetPosition(pushpin, location);
  5. ToolTipService.SetToolTip(pushpin, name);
  6. myMaps.Children.Add(pushpin);

 

Le code complet de la méthode SearchLocation :

  1. private async void SearchLocation(string query)
  2. {
  3.     myMaps.Children.Clear();
  4.  
  5.     string uri = "http://dev.virtualearth.net/REST/v1/Locations/" + query + "?maxResults=1&key=XXXXXXXXX";
  6.  
  7.     try
  8.     {
  9.         var client = new HttpClient();
  10.         var result = await client.GetStringAsync(uri);
  11.  
  12.         JsonValue value = Windows.Data.Json.JsonValue.Parse(result);
  13.  
  14.         var resources = value.GetObject()["resourceSets"].GetArray()[0].GetObject()["resources"].GetArray();
  15.  
  16.         Location firstLocation = null;
  17.  
  18.         foreach (var item in resources)
  19.         {
  20.             var name = item.GetObject()["name"].GetString();
  21.  
  22.             var coordinates = item.GetObject()["point"].GetObject()["coordinates"].GetArray();
  23.  
  24.             var latitude = coordinates[0].GetNumber();
  25.             var longitude = coordinates[1].GetNumber();
  26.  
  27.             var location = new Bing.Maps.Location(latitude, longitude);
  28.  
  29.             Pushpin pushpin = new Pushpin() { Text = "!" };
  30.  
  31.             MapLayer.SetPosition(pushpin, location);
  32.             ToolTipService.SetToolTip(pushpin, name);
  33.             myMaps.Children.Add(pushpin);
  34.  
  35.             if (firstLocation == null && resources.Count == 1)
  36.                 firstLocation = location;
  37.         }
  38.  
  39.         myMaps.SetView(firstLocation, 10, 10, TimeSpan.FromMilliseconds(1000));
  40.     }
  41.     catch
  42.     {
  43.         MessageDialog dialog = new MessageDialog("Unable to find location");
  44.         dialog.ShowAsync();
  45.     }
  46. }

 

L’évènement levé par une recherche utilisateur via le charm sera levé dans la classe App. Dans la classe MainPage, il nous faut ajouter un point d’entrée, qui permettra à l’application d’activer la recherche. Ajoutez une méthode statique Activate, qui récupère l’instance en cours de la page MainPage et qui appelle la méthode SearchLocation :

  1. public static void Activate(string queryText)
  2. {
  3.     var frame = Window.Current.Content as Frame;
  4.  
  5.     if (frame == null)
  6.     {
  7.         MainPage page = new MainPage();
  8.         page.SearchLocation(queryText);
  9.         Window.Current.Content = page;
  10.     }
  11.     else if (!(frame.Content is MainPage))
  12.     {
  13.         frame.Navigate(typeof(MainPage), queryText);
  14.     }
  15.     else
  16.     {
  17.         var mainPage = (MainPage)frame.Content;
  18.         mainPage.SearchLocation(queryText);
  19.     }
  20.  
  21.     Window.Current.Activate();
  22. }

 

La dernière étape consiste à récupérer l’évènement levé lorsque l’utilisateur effectue une recherche depuis le Charm et à appeler la méthode Activate que nous venons d’écrire. Pour se brancher sur la recherche, il suffit d’implémenter la méthode OnSearchActivated dans la classe App :

  1. protected override void OnSearchActivated(SearchActivatedEventArgs args)
  2. {
  3.     MainPage.Activate(args.QueryText);
  4. }

 

Vous pouvez maintenant tester la recherche. Déployer l’application, afficher le Charm et effectuer votre recherche.

Pour afficher le panel de recherche depuis notre application nous pouvons ajouter dans la page MainPage le bouton suivant dans le contrôle AppBar (à côté du bouton My Location) :

  1. <Button Click="btnSearch_Click" Style="{StaticResource SearchAppBarButtonStyle}" />

 

Voici le résultat visuel :

Bingmaps5

Et pour activer le panel de recherche depuis le code, il faut utiliser la classe Windows.ApplicationModel.Search.SearchPane comme ceci :

  1. private void btnSearch_Click(object sender, RoutedEventArgs e)
  2. {
  3.     Windows.ApplicationModel.Search.SearchPane.GetForCurrentView().Show();
  4. }

 

Nous en avons terminé pour la recherche d’un lieu. Dans la 3ème partie nous verrons comment récupérer et afficher la liste des incidents d’une zone géographique, ainsi que la recherche d’itinéraire.

En attendant, si vous recherchez plus d’informations sur le développement Windows 8, et plus particulièrement sur le Charm de recherche, je vous invite à consulter (en anglais) cet article de la MSDN, ainsi que les recommandations pour l’implémentation de ce Charm.

Et enfin, du côté des ressources françaises, retrouvez sur le site de la communauté Windows 8 une série d’articles sur l’implémentation des Charms.

Wednesday, July 04, 2012 7:15:49 PM (Romance Daylight Time, UTC+02:00)  #    Voir Commentaires
BingMaps | Windows 8
# Tuesday, July 03, 2012

Dans cet article en 3 parties (eh oui, finalement c’est 3 parties, et non 2…), je vous propose de découvrir comment utiliser le contrôle Bing Maps ainsi que les services REST Bing Maps dans une application Metro Windows 8 en XAML/C#.

Concernant la documentation, vous retrouvez sur la MSDN une section consacrée à l’utilisation du contrôle Bing Maps dans une application Metro et une autre section consacrée à l’utilisation des services REST Bing Maps.

Afin d’utiliser les services BingMaps, vous devez vous procurer une clé d’accès à ces services. Pour créer cette clé, ça se passe sur le portail BingMaps et voici la marche à suivre.

Maintenant que nous avons tous les prérequis, nous pouvons commencer…

Dans cette série d’article, nous allons découvrir :

  • comment insérer et manipuler une carte BingMaps dans une application Metro Windows 8 :
    • Changer de vue
    • Afficher le trafic
    • Centrer la carte par rapport à des coordonnées
    • Afficher, customiser, interagir avec des points d’intérêts comme ma localisation, des étapes d’un itinéraire, des incidents
  • comment utiliser les services REST afin de :
    • rechercher la localisation d’une adresse,
    • retrouver un itinéraire
    • retrouver la liste des incidents d’une zone

Voici le résultat que nous obtiendrons :

bingmaps1

 

Pour commencer, ouvrez Visual Studio 2012, et créez un nouveau projet vide de type Windows Metro style :

bingmaps2

2ème étape, il faut ajouter une référence vers le SDK Bing Maps, que vous avez préalablement installé…

bingmaps3

Une fois la référence ajoutée, si vous compilez le projet vous avez une erreur qui indique que la compilation “Any CPU” n’est pas supportée, ainsi qu’un Waring indiquant qu’il faut ajouter une référence vers Microsoft.VCLibs.

Allez dans les propriétés de compilation afin de sélectionner une nouvelle architecture cible, x86 par exemple, puis ajouter une référence vers l’assembly Microsoft.VCLibs qui correspond au Microsoft Visual C++ Runtime Package.

Nous sommes maintenant prêts à intégrer une carte dans notre application!

Ouvrez la page MainPage.xaml et ajoutez un contrôle de type Map à l’intérieur du contrôle Grid :

bingmaps4

Avant de pouvoir exécuter votre application, il vous faut tout d’abord nommer le contrôle Map et lui fournir la clé que vous avez précédemment créée :

  1. <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
  2.     <Maps:Map x:Name="myMaps" Credentials="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" />
  3. Grid>

 

Une fois ces informations renseignées, vous pouvez exécutez l’application. Le contrôle Map intègre de base la navigation à la souris, au clavier et au touch :

bingmaps5

Pour une description complète de la classe Map, je vous invite à consulter sa page MSDN associée.

Voici ici un exemple qui permet, depuis le code XAML :

  • d’afficher la carte en vue aérienne,
  • d’afficher les informations de trafic,
  • de masquer la légende de l’échelle,
  • d’initialiser la carte avec un zoom de niveau 17
  • de centrer la carte sur le point de coordonnées (48.830617,  2.261645)
  1.     <Maps:Map x:Name="myMaps"
  2.               Credentials="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
  3.               MapType="Aerial"
  4.               ShowTraffic="True"
  5.               ShowScaleBar="False"
  6.               ZoomLevel="17"
  7.               >
  8.         <Maps:Map.Center>
  9.             <Maps:Location Latitude="48.830617" Longitude="2.261645" />
  10.         Maps:Map.Center>
  11.     Maps:Map>
  12. Grid>

 

Maintenant, nous allons ajouter une AppBar qui va permettre à l’utilisateur :

  • de modifier le type de carte,
  • afficher/masquer le trafic,
  • centrer la carte sur la localisation de l’utilisateur et afficher un point d’intérêt

Tout d’abord, il faut ajouter les styles ci-dessous dans les ressources de la page. Ces styles vont nous permettre d’avoir de jolis boutons Metro pour notre barre d’application!

  1. <Style x:Key="TrafficAppBarButtonStyle" TargetType="Button" BasedOn="{StaticResource AppBarButtonStyle}">
  2.     <Setter Property="AutomationProperties.AutomationId" Value="TrafficAppBarButton"/>
  3.     <Setter Property="AutomationProperties.Name" Value="Traffic"/>
  4.     <Setter Property="Content" Value="⚠"/>
  5. Style>
  6. <Style x:Key="AerialAppBarButtonStyle" TargetType="Button" BasedOn="{StaticResource AppBarButtonStyle}">
  7.     <Setter Property="AutomationProperties.AutomationId" Value="AerialAppBarButton"/>
  8.     <Setter Property="AutomationProperties.Name" Value="Aerial"/>
  9.     <Setter Property="Content" Value="✈"/>
  10. Style>
  11. <Style x:Key="RoadAppBarButtonStyle" TargetType="Button" BasedOn="{StaticResource AppBarButtonStyle}">
  12.     <Setter Property="AutomationProperties.AutomationId" Value="RoadAppBarButton"/>
  13.     <Setter Property="AutomationProperties.Name" Value="Road"/>
  14.     <Setter Property="Content" Value="⛙"/>
  15. Style>
  16. <Style x:Key="BirdseyeAppBarButtonStyle" TargetType="Button" BasedOn="{StaticResource AppBarButtonStyle}">
  17.     <Setter Property="AutomationProperties.AutomationId" Value="BirdseyeAppBarButton"/>
  18.     <Setter Property="AutomationProperties.Name" Value="Birdseye"/>
  19.     <Setter Property="Content" Value=""/>
  20. Style>
  21. <Style x:Key="MyLocationAppBarButtonStyle" TargetType="Button" BasedOn="{StaticResource AppBarButtonStyle}">
  22.     <Setter Property="AutomationProperties.AutomationId" Value="MyLocationAppBarButton"/>
  23.     <Setter Property="AutomationProperties.Name" Value="My Location"/>
  24.     <Setter Property="Content" Value=""/>
  25. Style>

 

bingmaps6

Et enfin, voici le code l’AppBar à ajouter dans la MainPage :

  1. <Page.BottomAppBar>
  2.     <AppBar>
  3.         <Grid>
  4.             <StackPanel Orientation="Horizontal">
  5.                 <Button Click="btnTraffic_Click" Style="{StaticResource TrafficAppBarButtonStyle}" />
  6.                 <Button Click="btnAerial_Click" Style="{StaticResource AerialAppBarButtonStyle}" />
  7.                 <Button Click="btnRoad_Click" Style="{StaticResource RoadAppBarButtonStyle}" />
  8.                 <Button Click="btnBirdseye_Click" Style="{StaticResource BirdseyeAppBarButtonStyle}" />
  9.             StackPanel>
  10.             <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
  11.                 <Button Click="btnMyLocation_Click" Style="{StaticResource MyLocationAppBarButtonStyle}" />
  12.             StackPanel>
  13.         Grid>
  14.     AppBar>
  15. Page.BottomAppBar>

 

Pour les changements de vue de la carte, il suffit de modifier la propriété MapType du contrôle Map et de lui affecter une valeur de l’énumération Bing.Maps.MapType comme ceci :

  1. private void btnAerial_Click(object sender, RoutedEventArgs e)
  2. {
  3.     myMaps.MapType = Bing.Maps.MapType.Aerial;
  4. }
  5.  
  6. private void btnRoad_Click(object sender, RoutedEventArgs e)
  7. {
  8.     myMaps.MapType = Bing.Maps.MapType.Road;
  9. }
  10.  
  11. private void btnBirdseye_Click(object sender, RoutedEventArgs e)
  12. {
  13.     myMaps.MapType = Bing.Maps.MapType.Birdseye;
  14. }

 

Pour afficher/masquer le trafic, il suffit de modifier la valeur de la propriété ShowTraffic :

  1. private void btnTraffic_Click(object sender, RoutedEventArgs e)
  2. {
  3.     myMaps.ShowTraffic = !myMaps.ShowTraffic;
  4. }

 

Pour utiliser l’API de géolocalisation, il faut tout d’abord autoriser l’application à le faire. Depuis l’explorateur de solution, ouvrez le fichier Package.appxmanifest, puis dans l’onglet Capabilities, cochez la case Location :

bingmaps7

 

Pour plus d’informations sur la notion de Capabilities, je vous invite à consulter l’article correspondant sur la MSDN.

Pour utiliser l’API de géolocalisation, nous avons besoin d’une instance de la classe Geolocator dans l’espace de nom Windows.Devices.Geolocation. Cette classe possède une propriété LocationStatus que nous pouvons utiliser de cette manière :

  1. var geolocator = new Geolocator();
  2. if (geolocator.LocationStatus == PositionStatus.NotAvailable)
  3. {
  4.     MessageDialog dialog = new MessageDialog("Location service not available");
  5.     dialog.ShowAsync();
  6.     return;
  7. }

 

Ensuite, pour localiser l’utilisateur et ainsi récupérer les coordonnées géographiques, il faut utiliser la méthode GetGeopositionAsync comme ceci :

  1. Geoposition position = await geolocator.GetGeopositionAsync();

 

La méthode GetGeopositionAsync retourne un objet de type GeoPosition (ou plutôt IAsyncOperation), grâce auquel nous pouvons récupérer la latitude et la longitude.

Pour utiliser des coordonnées géographiques sur le contrôle Map, nous avons besoin d’un objet de type Location de l’espace de nom Bing.Maps.Location :

  1. Location location = new Bing.Maps.Location(position.Coordinate.Latitude, position.Coordinate.Longitude);

Un point d’intérêt sur un contrôle de type Map est représenté par un objet de type Pushpin, qu’il faut positionner via la classe MapLayer, puis l’ajouter  à la collection Children du contrôle Map :

  1. Pushpin pushpin = new Pushpin() { Text = "!" };
  2. MapLayer.SetPosition(pushpin, location);
  3. myMaps.Children.Add(pushpin);

 

Enfin, nous pouvons centrer la carte sur ce point d’intérêt et y ajouter un tooltip :

  1. ToolTipService.SetToolTip(pushpin, "My location");
  2. myMaps.SetView(location, 12);

 

Ici nous utilisons la méthode SetView de l’objet Map pour centrer la carte sur les coordonnées géographiques spécifiées. Le second paramètre permet de définir le niveau de zoom. Le contrôle animera la carte automatiquement pour obtenir ce niveau de zoom et cette position.

Voici le code complet de la méthode de recherche de localisation :

  1.     private async void btnMyLocation_Click(object sender, RoutedEventArgs e)
  2.     {
  3.         Geoposition position = null;
  4.         try
  5.         {
  6.             var geolocator = new Geolocator();
  7.             if (geolocator.LocationStatus == PositionStatus.NotAvailable)
  8.             {
  9.                 MessageDialog dialog = new MessageDialog("Location service not available");
  10.                 dialog.ShowAsync();
  11.                 return;
  12.             }
  13.             position = await geolocator.GetGeopositionAsync();
  14.         }
  15.         catch
  16.         {
  17.             MessageDialog dialog = new MessageDialog("Unable to find your location");
  18.             dialog.ShowAsync();
  19.             return;
  20.         }
  21.  
  22.         if (position == null)
  23.             return;
  24.  
  25.         Location location = new Bing.Maps.Location(position.Coordinate.Latitude, position.Coordinate.Longitude);
  26.         Pushpin pushpin = new Pushpin() { Text = "!" };
  27.         MapLayer.SetPosition(pushpin, location);
  28.         myMaps.Children.Add(pushpin);
  29.         ToolTipService.SetToolTip(pushpin, "My location");
  30.         myMaps.SetView(location, 12);
  31.     }
  32. }

bingmaps8

Dans la 2ème et 3ème partie de cet article, nous découvrirons les services REST Bing Maps qui vont nous permettre d’intégrer la recherche d’adresse, d’itinéraire et d’incidents.

En attendant, si vous avez besoin de plus de détails sur certaines notions non détaillées dans cet article (mots clés async/await, notion de style et d’AppBar…) je vous invite à consulter les articles présents sur le site de la communautés des Développeurs Windows 8.

Et si vous avez des questions sur le développement Windows 8, n’hésitez pas à les poster sur le groupe Facebook de la communauté Windows 8.

Tuesday, July 03, 2012 1:56:31 PM (Romance Daylight Time, UTC+02:00)  #    Voir Commentaires
BingMaps | Windows 8
# Wednesday, June 20, 2012

Bing_Maps_blue20logo1-300x82BingMaps met à disposition des développeurs des services et des API leurs permettant d’intégrer des fonctionnalités de géolocalisation dans leurs applications Web, Silverlight, WPF, Metro…

Je vous invite demain, jeudi 21 juin, à 12h30, à La Cantine de Toulouse pour un Techlunch qui vous fera découvrir ces différents services. Je vous présenterai notamment l’intégration des services Bing Maps dans une application Windows 8 Metro.

Il n’est pas trop tard pour vous inscrire!

Wednesday, June 20, 2012 10:56:39 AM (Romance Daylight Time, UTC+02:00)  #    Voir Commentaires
BingMaps | Windows 8
# Sunday, June 10, 2012

Vendredi Microsoft a dévoilé sa nouvelle offre autour des services Windows Azure avec notamment une offre de type IAAS qui vient concurrencer l’offre EC2 d’Amazon.

Avec les services de machine virtuelle, il est maintenant possible de déployer son serveur SharePoint, SQL Server ou encore Linux dans le Cloud de Microsoft, car ces machines virtuelles sont persistantes, contrairement aux VM Roles de l’offre PAAS. Avec un nouveau portail de gestion de ses services Azure développé en HTML5, il est possible de déployer un serveur Linux ou un Windows Server 2012 en quelques secondes et de bénéficier de l’élasticité du Cloud Computing.

La création d’une machine virtuelle peut se fait à partir d’un catalogue (SQL Server 2012, Windows Server 2008 R2, 2012, CentOS, SUSE, Ubuntu, OpenSUSE) ou à partir d’un VHD en votre possession.

NewPortalVM2

 

Microsoft a également annoncé une offre d’hébergement de site Web avec des technologies telles que ASP.NET, PHP, Node.js et MySQL. Il est également possible de créer un site web en quelques secondes grâce à un catalogue de solutions connues (WordPresse, Joomla!, DasBlog, DotNetNuke…) :

NewPortalWebSite2

 

A noter également l’abandon du portail Silverlight qui est remplacé par un portail HTML5 et une ergonomie revue au style Metro :

  NewPortal

Rendez-vous dans la section des fonctionnalités du site Windows Azure pour découvrir toutes les nouveautés des services de Cloud Computing de Microsoft (Services multimédias, Machine Virtuelle, Site Web, Décisionnel, Active Directory…).

Sunday, June 10, 2012 3:54:18 PM (Romance Daylight Time, UTC+02:00)  #    Voir Commentaires
Azure | Windows Azure
# Tuesday, June 05, 2012

logo

Ce weekend, Microsoft France a organisé un événement autour du développement Windows 8 à Paris, le DevKing 2012.

Au menu, l’accélérateur Windows 8, le concours BeMyApps, des Fast Code à n’en plus dormir.

Côté animation, de super burger, du Red Bull à volonté pour tenir éveillé, des séances massage, des DJs, des jeux vidéos…

Plus de 100 personnes de divers horizons, étudiants, éditeurs, SSII, tous des Geeks en somme, sont venus s’affronter et s’amuser à travers ces différents concours.

Les différentes applications que nous avons pu y voir sont vraiment de très bonne qualité, et laisse présager un MarketPlace Windows 8 de haute couture… A ce propos, si vous n’avez pas encore testé Windows 8, sachez que la Release Preview (équivalent de Release Candidate) de Windows 8 est disponible en téléchargement depuis la semaine dernière.

De notre côté, nous nous étions constitués une petite Team, pur produit du sud ouest, avec mes amis Seb, Cyril et Loïs. Objectif : prendre beaucoup de plaisir, mais aussi arracher la victoire sur au moins un Fast Code.

Objectif réussi!! Nous avons développé une application autour des services de Facebook que nous avons appelée : Incrustator. Je ne vous en dit pas plus, mais vous retrouverez certainement cette application sur le Market de Windows 8…

168504_3420918561207_1045283009_n

Tuesday, June 05, 2012 10:16:23 AM (Romance Daylight Time, UTC+02:00)  #    Voir Commentaires
Windows 8
# Thursday, March 22, 2012

image

Si vous n’avez pas encore installé Windows 8 et testé le développement d’applications Metro avec Visual Studio 11, alors le moment est venu !

Microsoft organise au mois d’avril un DevCamp dans 8 villes de France et nous aurons l’occasion de nous croiser dans le sud à Bordeaux (05/04), Toulouse (26/04) et Marseille (19/04).

Au programme de la journée, travaux pratiques sur le développement d’application Windows 8 avec Visual Studio 11, nous sommes là pour vous aider et répondre à vos questions.

L’évènement est gratuit, il vous faut venir avec votre PC et les prérequis installés, Windows 8 et Visual Studio 11, disponible en téléchargement ici : http://msdn.microsoft.com/fr-fr/windows/apps.

Rendez-vous sur le site des DevCamps pour vous inscrire dans votre ville : http://msdn.microsoft.com/fr-fr/devcamp

Thursday, March 22, 2012 4:29:35 PM (Romance Standard Time, UTC+01:00)  #    Voir Commentaires
Windows 8
# Friday, February 24, 2012

imageCette année je n’étais pas présent sur le parcours ALM mais sur le parcours Windows Phone.

Du côté ALM, Bewise a présenté un témoignage client, basée sur notre expérience projet avec Airbus. Cette session a été animé par Sacha Leroux (Bewise) et Christophe Vignolle, chargé de diriger les projets liés au marketing et à la vente d’avions chez Airbus.

Bien évidemment le parcours ALM proposait une multitude de sessions : Qualité logicielle, industrialisation, automatisation, tests fonctionnels, lab management... Vous pouviez également découvrir les nouveautés de Visual Studio 11 aux côtés de Florent Santin et Etienne Margraff.

 

Du côté du développement Windows Phone, avec Christopher Maneu nous avons présenter le développement d’une application métier/d’entreprise sur WP7.5. Pendant cette session nous avons démontré que les nouvelles fonctionnalités disponible avec Mango permettent de développer des applications pour les entreprises répondant à leurs contraintes (sécurité, confidentialité, modularité, saisie au Km…). Le tableau ci-dessous résume assez bien les besoins métiers et les API utilisées :

image

 

Et enfin, avec Sébastien Pertus, nous avons présenté l’utilisation d’une base de données SQL CE dans une application WP7.5. L’utilisation d’une base de données SQL CE sur Windows Phone nécessite le développement d’un modèle Linq To SQL en Code First. Nous avons également parlé des problématiques de déploiement, de migration et de synchronisation.

Le contenu des Techdays (webcast, slides) sera disponible courant mars, sur le site http://www.microsoft.com/france/mstechdays. Pour vous divertir je vous conseille fortement de visionner la session Coding4Fun (que l’on ne présente plus) mais également la session “The geek is in da house! Comment se faire la maison du futur avant les autres!” avec un David Catuhe en pleine forme!

Friday, February 24, 2012 11:05:34 AM (Romance Standard Time, UTC+01:00)  #    Voir Commentaires
Techdays 2012
# Friday, December 23, 2011

image

Si vous aussi vous rechercher une solution pour effectuer des recherches dans les fichiers de code source de TFS, voici un article qui devrait vous intéresser.

Dans cet article, nous mettons en place une solution d’indexation des source TFS basée sur la recherche Full Text de SQL Server et Team Build.

Friday, December 23, 2011 11:37:38 AM (Romance Standard Time, UTC+01:00)  #    Voir Commentaires
TFS
# Monday, June 27, 2011

imageSuite à la sortie du Kinect Windows SDK, Microsoft France organise demain, mardi 28 juin, un après midi du développement pour vous faire découvrir ce SDK. Alors si vous n’êtes pas encore inscrits, dépêchez-vous, ça se passe par ici.

Je présenterai pour ma part le pilotage d’une scène 3D temps réel avec Kinect.

Monday, June 27, 2011 5:02:28 PM (Romance Daylight Time, UTC+02:00)  #    Voir Commentaires
Kinect
Archive
<July 2012>
SunMonTueWedThuFriSat
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2013
Benoît Laut
Sign In
All Content © 2013, Benoît Laut
DasBlog theme 'Business' created by Christoph De Baene (delarou)