En vrac lundi 9 janvier 2012

Une de mes « résolutions » pour 2012 c’est d’écrire plus ici et perdre moins mon temps ailleurs (je passe sur les détails). Comme tous les jours je lis des tonnes d’information, je me suis dit que j’allais tester le format « en vrac » et vous en faire un résumé ici. C’est un test, on va voir ce que ça donne.

Commençons par une nouveauté Windows Phone 7 qui date de quelques jours : l’ouverture des marchés Argentine, Chine, Indonésie, Malaisie, Pérou et Philippines. Ça fait donc 41 marchés disponibles pour la publication de vos applications WP7 ! Alors que pour certains cette nouvelle est particulièrement intére$$ante, pour moi ce qui m’attire le plus c’est les nouveaux défis des concepteurs d’applications. Le développement globalisé impose d’être de plus en plus culture-sensitive, ce qui est loin d’être évident. Prenez, par exemple, les nouvelles restrictions à prendre en compte si vous visez les marchés chinois, indonésien ou malaisien :

  • People in revealing clothing or sexually suggestive poses
  • Religious references
  • Alcohol references
  • Sexual or bathroom humor
  • Simulated or actual gambling

C’est moi qui ai surligné certains mots clés qui pourraient ne pas être évidents pour les développeurs W.E.I.R.D.

 

Une mauvaise nouvelle en rapport avec Windows Phone, par contre : l’équipe à annoncé sur leur blog qu’ils arrêtent le service Where’s My Windows Phone Update? qui annonçait la date de sortie des mises à jour du système d’exploitation. Ce manque de transparence indiquerait-il le début de la fragmentation sous WP7 ?

Ensuite, une autre nouvelle de chez Microsoft, mais Microsoft Research cette fois-ci. Il s’agit du projet Vermeer, un affichage en 3D dimensions visible sur 360° par multiples utilisateurs simultanés, sans nécessité de lunettes ou autres accessoires. Ah, et j’oubliais, il est possible d’utiliser ses mains pour interagir avec. Une vidéo vaut plus que tous mes mots :

Dans un registre un peu différent, la NASA annonce le lancement de code.NASA.gov, un portail pour exposer les différents projets open source de l’agence américaine et encourager la participation du public. C’est une version alpha du site ; toutes les fonctionnalités (genre, contrôle de codes sources distribué) ne sont pas encore là, et je pense que tous les projets me dépassent, personnellement, mais je trouve l’initiative excellente. J’aimerais bien que mes impôts soient utilisés comme ça, moi.

Alors que CES n’a même pas commencé, mon Google Reader est déjà rempli d’annonces pour la plupart inintéressantes (qu’est-ce que j’en ai à faire d’une télé qui coûte €6000 ?), mais Engadget a publié des photos d’un truc que je dois partager ici : le Thermador Freedom. Il s’agit d’une table de cuisson à induction qui vous permet de poser vos casseroles et autres ustensiles où vous voulez, détectant leur forme et placement et vous permettant de régler la température de chacune selon leur position.

Autant la 3D je m’en fous royalement, autant pour un truc comme ça je suis prêt à payer les $4949 que ça va apparemment coûter lors de sa sortie cet été. Je vous laisse cliquer sur la photo pour aller chez Engadget pour plus de détails et de photos.

Encore une nouvelle CES, la société Vizio qui est apparemment connue pour ses produits home cinema, se lance dans le marché des PCs voulant concurrencer Apple en proposant un truc que l’on voit rarement : des jolis PCs !

J’espère que la qualité matérielle et les performances seront à l’appel aussi. En revanche, s’ils pouvaient éviter les prix Apple, ce serait sympa.

Enfin, un article qui pourrait être mal pris, mais avec lequel je suis plutôt d’accord. Vint Cerf déclare dans un édito du New York Times qu’Internet n’est pas un droit fondamental. Je trouve que cet extrait résume assez bien l’article (que je vous encourage à lire tout de même) :

It is a mistake to place any particular technology in this exalted category, since over time we will end up valuing the wrong things. For example, at one time if you didn’t have a horse it was hard to make a living. But the important right in that case was the right to make a living, not the right to a horse. Today, if I were granted a right to have a horse, I’m not sure where I would put it.

Et voilà un résumé de mes lectures de la journée, en vrac. Si ça plaît, je continuerai. Si ça ne plaît pas, je vais probablement continuer quand même, juste pour l’exercice. La fréquence et la longueur dépendront de plein de choses, on verra donc avec le temps comment ces billets évoluent.

Sortie d’une version web du Marketplace Windows Phone

Le Marketplace de Windows Phone 7 est pas mal sur le téléphone, voire aussi sur l’application Zune. En revanche, il n’existait pas de version web. Jusqu’aujourd’hui !

Pourquoi faire ?

Parce que c’est pratique. J’aime bien le petit écran de mon téléphone, mais j’aime aussi l’écran de mon PC. Il est bien pour avoir plus d’information à la fois. Un site qui permet de recherches des applications, les acheter et les envoyer sur le téléphone depuis un navigateur quelconque et depuis n’importe quel PC est donc le bienvenu.

Il existe la même chose pour les téléphones Android depuis le début de l’année, l’Android Market. C’est bien de voir que Microsoft ne traîne pas sur tout ce qui concerne WP7 en fin de compte 😉

Le Marketplace de Microsoft à l’air pas mal dans l’ensemble, il y a juste un détail qu’on aurait bien aimé qu’ils copient chez Android :

Mais bon, il ne fallait pas rêver. Entre temps, éditeur, date de mise à jour, version, langues, évaluations, screenshots et, surtout, un bouton pour acheter/installer, tout est là. Bon travail Microsoft 😉

(Via Electricpig)

WP7 Mango : Faut-il faire des mises à jour ? Et que se passe-t-il si je les fais ?

mangoPour le grand public ce sera Windows Phone 7.5—parce que le marketing l’a décidé ainsi. Pour nous, développeurs, ce que nous connaissons aujourd’hui sous le nom code “Mango” sortira bientôt sous le nom officiel Windows Phone OS 7.1—parce que chez Microsoft on sait nommer ses classes et ses méthodes, mais pas ses produits.

Un nouvel OS arrive, mais nous savons bien que Microsoft fait toujours un effort surhumain pour faire en sorte que les vielles applications marchent correctement sur les nouvelles versions de ses systèmes d’exploitation, donc il est pertinent de se poser la question :

Dois-je mettre à jour mon application 7.0 puisqu’elle marchera automatiquement sous 7.1 ?

La réponse est un peu dans la question : non, vous n’êtes pas obligés de faire de mise à jour. Enfin, sauf si vous vouliez que votre application marche mieux et ce avec seulement une ligne de code (lignes des accolades non comprises) !

Je m’explique. Vous vous souvenez du temps que vous avez passé pour faire en sorte que votre application survive le tombstoning correctement ? Vous devez enregistrer l’état de l’application quand elle est désactivée—peu importe la raison—et le restaurer quand est réactivée—peu importe la raison. Ça rend votre application plus agréable à utiliser, mais vous aurez probablement remarqué que la réactivation peut parfois être longue.

Il se trouve que sous Mango, vos processus ne sont plus systématiquement tués par l’OS et donc l’état n’est plus systématiquement perdu ce qui rend sa restitution à chaque réactivation un peu redondant. Heureusement, nous avons un moyen de déterminer si les données sont toujours là et donc nous ne sommes plus obligés de restaurer l’état de l’application que si c’est absolument nécessaire.

private void Application_Activated(object sender, ActivatedEventArgs e)
{
  if (!e.IsApplicationInstancePreserved)
  {
    var state = PhoneApplicationService.Current.State;

    if (state.ContainsKey("myStateData"))
    {
      this.data = (string)state["myStateData"];
    }
  }
}

La valeur de la propriété IsApplicationInstancePreserved sera true si l’application, et donc son état, étaient déjà en mémoire. Dans ce cas, il n’y a plus besoin de rien faire, dans le cas contraire on restaure l’état comme on le faisait avant. Et voilà, en une ligne vous avez accéléré le chargement de votre application.

Et maintenant que vous avez une application Mango, que se passe-t-il sur le Marketplace ?

Microsoft a veut visiblement limiter la fragmentation et veut pousser les utilisateurs à faire la migration de leur OS donc une fois que vous avez publié une version Mango de votre application, vous ne pourrez plus mettre à jour la version 7.0 sur le Marketplace. Bien ? Mal ? Je trouve que c’est une mesure un peu drastique, mais je suis plutôt à faveur.

La dernière version 7.0 de votre application sera toujours disponible—bugs et tout—pour les utilisateurs qui sont toujours sur cette plateforme. Tous ceux qui auront migré ne pourront télécharger que la version Mango.

Les utilisateurs qui avaient déjà installé votre application et qui migrent sous Mango, recevront une notification de mise à jour et pourront installer la nouvelle version de votre application. Ceux qui décident de rester sous 7.0 n’auront pas de mise à jour.

Les métadonnées seront communes aux deux versions de l’application en revanche, y compris les screenshots. Microsoft recommande donc d’être très clairs dans les descriptions des applications et de signaler les fonctionnalités qui ne seront disponibles que sous Mango. Ils suggèrent aussi que vous deveniez ambassadeur-malgré-vous en mettant dans vos descriptions un lien vers http://wpupgrade.ms/mangome pour inciter les utilisateurs à faire la mise à jour du téléphone. Pour les screenshots, vous êtes encouragés à utiliser un watermark identifiant les images qui montrent des fonctionnalités disponibles “Uniquement sous WP 7.5”.

Comment dit-on Windows Phone 7 en français ?

Windows Phone 7, bien sûr !

Si vous avez déjà développé des applications en plusieurs langues, par contre, vous savez qu’il y a des traductions qui sont moins évidentes. Et encore, le français, vous le maîtrisez peut-être, mais l’allemand, par exemple, savez-vous dire tile ou vignette en allemand ? La bonne réponse est Kachel.

Mon outil préféré pour ce genre de traductions est le portail linguistique de Microsoft. Vous pouvez y faire des recherches, qui vous retourneront des résultats avec leur contexte et vous pourrez aussi filtrer par produit:

Mais les traductions « mot à mot » sont rarement suffisantes et chaque application, chaque plateforme va avoir ses spécificités. C’est pour ça que Microsoft a sorti 5 guides de style pour donner des conseils sur comment écrire pour Windows Phone 7 en :

Que dit-on à la place de oops en français ? Doit-on dire please ou son équivalent français, veuillez ? À ce sujet, on tutoie ou on vouvoie un utilisateur de Windows Phone ? En allemand, tout en minuscules ou respecte-t-on la grammaire tudesque ? Vous trouverez les réponses à toutes ces questions et bien d’autres dans ces PDFs.

Création de nouvelles pages et navigation sur Windows Phone 7

Ceci est le sixième billet d’une série sur Windows Phone 7 dans laquelle je construis une application permettant de surveiller la disponibilité de vélos des stations Vélib’ à Paris. Pour rappel, voici la table de matières:

  1. Introduction et installation des outils
  2. Création d’une application et utilisation du contrôle Bing Maps
  3. Le GPS et les services de géolocalisation
  4. Consommation d’un service OData
  5. Ajout de punaises sur une carte Bing Maps
  6. Création de nouvelles pages et navigation
  7. Création de vignettes sur la page d’accueil

Un modèle de programmation Web

Screenshot 2

Vous avez surement remarqué l’absence de fenêtres dans notre application Windows Phone 7. Cela aurait pu vous marquer, notamment si vous êtes habituées au développement sur environnements desktop, voire aussi sur des anciennes versions de Windows Mobile.

Si je devais faire un parallèle entre le développement sur Windows Phone 7 et une autre plateforme, je me verrais obligé de le comparer au développement Web—en tout cas pour ce qui est des applications Silverlight ; les application XNA sont une toute autre histoire.

En effet, si vous examinez le code généré dans le fichier App.xaml.cs vous trouverez qu’au démarrage de l’application on commence par déclarer comme élément racine un objet de type PhoneApplicationFrame. C’est dans ce frame que vont être affichées par la suite vos pages, qui dérivent de la classe PhoneApplicationPage. Le similitudes ne se limitent pas au frame et aux pages. Vous verrez qu’on retrouvera des concepts tels que les URIs, les hyperliens, etc.

Une nouvelle page

Hier nous avons permis à l’utilisateur d’afficher des stations sur sa carte. Il est même capable d’appuyer sur l’une de ces dernières et, de notre côté, nous savons identifier la station qu’il a sélectionnée, mais il nous manque quelque chose pour en afficher les détails.

Ajoutez à votre projet un nouvel élément. Sélectionnez une nouvelle Windows Phone Portrait Page parmi les templates Silverlight for Windows Phone.

Add New Item - UnVelo.Wp7

La page créée ressemble à la page principale lorsque nous avons démarré le projet.

Cette fois-ci, nous allons travailler sur le modèle par défaut en remplaçant certaines valeurs et en le complétant avec les contrôles nécessaires pour obtenir un affichage comme celui sur la capture au début de ce billet.

Commençons par modifier la partie du haut :

<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
    <TextBlock x:Name="ApplicationTitle" Text="UN VELO.FR"
               Style="{StaticResource PhoneTextNormalStyle}"/>
    <TextBlock x:Name="PageTitle" Text="{Binding Number, StringFormat='Station {0}'}"
               Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>

Le nom de l’application sera une valeur constante, en revanche, le titre devra afficher le numéro de station. Nous utilisons donc une expression de binding pour afficher la propriété Number de la classe Station. Petite nouveauté “Mango” : comme on utilise enfin Silverlight 4, nous avons accès à la propriété StringFormat de l’expression de binding, ce qui nous permet de personnaliser un peu le texte affiché sans passer par des convertisseurs ou des piles de TextBlocks.

En raison de ce qui semblerait être un bug dans le contrôle Bing Maps, je n’ai pas pu placer tous mes contrôles dans le ContentPanel fourni pour cet effet. J’ai donc modifié le LayoutRoot :

<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <Grid.Resources>
        <local:StationConverter x:Key="StationConverter" />
    </Grid.Resources>
<!-- ... -->

En y ajoutant une ligne, j’ai pu placer la carte juste au dessus du ContentPanel :

<map:Map Margin="12,0,12,0" Grid.Row="1" Grid.ColumnSpan="2" Height="250"
        CredentialsProvider="{StaticResource BingMapsKey}" ZoomLevel="16"
        Center="{Binding Converter={StaticResource StationConverter}}">
    <map:MapItemsControl x:Name="pins"
        ItemsSource="{Binding Converter={StaticResource StationConverter}}">
        <map:MapItemsControl.ItemTemplate>
            <DataTemplate>
                <map:Pushpin Location="{Binding Location}" />
            </DataTemplate>
        </map:MapItemsControl.ItemTemplate>
    </map:MapItemsControl>
</map:Map>

<!--ContentPanel - place additional content here-->
<StackPanel x:Name="ContentPanel" Grid.Row="2" Margin="12,12,12,0">
    <TextBlock Text="{Binding Name}"
               FontFamily="{StaticResource PhoneFontFamilySemiBold}"
               FontSize="{StaticResource PhoneFontSizeLarge}"
               Foreground="{StaticResource PhoneAccentBrush}" />
    <TextBlock Style="{StaticResource PhoneTextLargeStyle}"
      Text="{Binding AvailableBikes, StringFormat='Vélos disponibles : {0}'}" />
    <TextBlock Style="{StaticResource PhoneTextLargeStyle}"
      Text="{Binding FreeSpaces, StringFormat='Places disponibles : {0}'}" />
</StackPanel>

Le code ci-dessus est moins complexe qu’il ne parait. Certes, la présence d’un converter dans les bindings vous perturbe certainement un peu et le rendu fait par le designer est assez décevant :

ViewHolder2

Tous les bindings ont été faits en supposant qu’un objet de type Station se trouve dans le DataContext de la page. Or nous n’avons pas encore défini de station, donc rien ne s’affiche.

On a besoin d’une station !

Naviguer entre les pages

Revenons sur la page principale ; plus spécifiquement, dans le gestionnaire de l’évènement Tap des punaises :

private void OnStationTap(object sender, GestureEventArgs e)
{
    var station = (sender as Pushpin).DataContext;
}

Nous avons une station dont nous voulons afficher les détails.

Pas question ici de créer une nouvelle instance de la classe que nous venons de créer. Je vous rappelle que nous sommes dans un modèle type Web et nous allons tout simplement naviguer entre les pages comme nous l’aurions fait avec des documents HTML.

Pour cela, nous avons à notre disposition un NavigationService qui est accessible par la propriété homonyme de vos pages. Ce service propose une méthode Navigate qui prend en paramètre un URI relatif vers la destination :

private void OnStationTap(object sender, GestureEventArgs e)
{
    var station = (sender as Pushpin).DataContext;

    NavigationService.Navigate(new Uri("/DetailsPage.xaml", UriKind.Relative));

    // Dans la version ci-dessous on spécifie l'assembly (UnVelo.Wp7)
    // Cela peut-être utile si vos pages se trouvent dans un assembly
    // différent de celui en cours d'exécution
    // NavigationService.Navigate(new Uri("/UnVelo.Wp7;component/DetailsPage.xaml", UriKind.Relative));
}

Le code ci-dessus (les deux versions) produit l’effet désiré : le téléphone change de page et affiche celle que nous avons préparée plus haut. De plus, la page principale a été placée sur la pile de navigation, ce qui nous permet d’y retourner via le bouton Précédent.

En revanche, le code ne fait que ça : passer la page ; et comme nous n’instancions pas la page nous-mêmes, il n’y a, a priori pas de moyen de passer des données via des propriétés de la page comme on a l’habitude de le faire sous d’autres plateformes.

Transmission de données entre les pages

Il y a deux manières de passer des données en mémoire d’une page à une autre : la query string (comme dans le Web) et l’état courant du PhoneApplicationService.

Comme dans une page web, on peut passer des informations dans l’URI de la page appelée, par exemple, dans la page principale on écrit :

private void OnStationTap(object sender, GestureEventArgs e)
{
    var pin = ((sender as Pushpin).DataContext as Pin);

    var uri = string.Format("/DetailsPage.xaml?id={0}", pin.Station.Number);
    NavigationService.Navigate(new Uri(uri, UriKind.Relative));
}

Et dans la page détails on peut récupérer la valeur avec le code suivant :

public override void OnNavigatedTo(NavigationEventArgs e)
{
    var number = NavigationContext.QueryString["id"];

    // ...

    base.OnNavigatedTo(e);
}

La méthode OnNavigatedTo de la page est appelée lorsque l’on arrive sur une page—son opposé est OnNavigatedFrom, qui est appelée juste avant que l’on quitte une page. Dans cette méthode on pourrait récupérer les différentes valeurs qui ont été passées dans la query string pour les assigner aux contrôles de la page ou pour effectuer des data bindings.

Toutefois, dans l’exemple qui nous concerne, nous voulons passer bien plus d’informations que juste le numéro de station, et nous avons toutes ces informations encapsulées dans une instance de la classe Station. De plus, il peut exister des cas où les données qui doivent être partagées entre les pages ne peuvent pas être transformées en chaine de caractères pour être concaténées à l’URI de la page. Pour ces cas-là, la classe PhoneApplicationService mantient un état courant dans lequel on peut stocker des objets pour les partager entre plusieurs pages :

private void OnStationTap(object sender, GestureEventArgs e)
{
    var pin = ((sender as Pushpin).DataContext as Pin);

    PhoneApplicationService.Current.State["currentStation"] = pin.Station;

    NavigationService.Navigate(new Uri("/DetailsPage.xaml", UriKind.Relative));
}

Les lignes ci-dessus enregistrent dans un emplacement de l’état courant de l’application, que l’on appelle arbitrairement currentStation, la station contenue dans le DataContext de la punaise qui a été appuyée par l’utilisateur. Du côté de la page de détails, quelques lignes suffiront à récupérer cet objet pour afficher les informations qu’il contient :

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    object station;

    if (PhoneApplicationService.Current.State.TryGetValue("currentStation", out station))
    {
        this.DataContext = station;
    }

    base.OnNavigatedTo(e);
}

On aurait pu se contenter de faire tout simplement l’assignation :

this.DataContext = PhoneApplicationService.Current.State["currentStation"];

Mais l’utilisation de la méthode TryGetValue maintenant nous permettra de prévoir des cas où il n’y a pas de valeur pour la clé currentStation à l’avenir.

Grâce aux bindings que nous avions déclarés lorsque nous avons créé la page de détails, le fait d’assigner un objet de type Station à son DataContext suffit à afficher la page comme on le voulait.

Details_page

Si vous essayez d’exécuter le code il vous manquera cependant la classe StationConverter que nous avons utilisée pour simplifier certains bindings :

public class StationConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var station = value as Station;

        if (null == station)
        {
            return value;
        }

        if (typeof(GeoCoordinate) == targetType)
        {
            return new GeoCoordinate((double)station.Latitude, (double)station.Longitude);
        }
        else if (typeof(IEnumerable) == targetType)
        {
            return new object[] { new Pin { Station = station } }.AsEnumerable();
        }

        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Nous approchons de la fin de la série. Maintenant que nous avons réussi à afficher les détails d’une station dans une page, nous allons profiter d’une des nouveautés de “Mango” qui nous permettra de modifier, à partir du code uniquement, des vignettes sur la page d’accueil pour y afficher, par exemple, le nombre de vélos disponibles dans une station. Mais ce code-là, on le verra demain.

Ajout de punaises sur une carte Bing Maps

Ceci est le cinquième billet d’une série sur Windows Phone 7 dans laquelle je construis une application permettant de surveiller la disponibilité de vélos des stations Vélib’ à Paris. Pour rappel, voici la table de matières:

  1. Introduction et installation des outils
  2. Création d’une application et utilisation du contrôle Bing Maps
  3. Le GPS et les services de géolocalisation
  4. Consommation d’un service OData
  5. Ajout de punaises sur une carte Bing Maps
  6. Création de nouvelles pages et navigation
  7. Création de vignettes sur la page d’accueil

On a besoin de punaises

Hier nous nous sommes arrêtés sur une liste stations. Chaque station est représentée par un objet de type Station qui contient des propriétés telles que le numéro de station, son adresse, le nombre de vélos et de places disponibles, mais surtout, ses coordonnées géographiques.

La prochaine étape sera donc d’utiliser ces informations pour afficher des punaises sur la carte de la page principale qui donneront un aperçu de l’état de chaque station et qui nous permettront d’accéder à la page de détails de celles-ci.

Pour afficher des punaises sur une carte, vous allez utiliser des calques. Ces calques dérivent de MapLayer et supportent des éléments d’à peu près n’importe quel type:

custom_pins

Dans notre cas, le Pushpin fourni dans l’assembly Bing Maps suffira largement. Ce contrôle possède deux propriétés qui nous intéressent :

Taj_Mahal

  • Content : est une propriété héritée de ContentControl qui permet à la classe Pushpin d’afficher à peu près n’importe quel contenu.
  • Location : est de type GeoCoordinate et représente les coordonnées géographiques de la punaise qui serviront à la positionner sur la carte.
<map:Pushpin Content="Taj Mahal" Location="27.172222,78.042476" />

Cependant, notre modèle de données, la Station, ne correspond pas tout à fait à ce qui est attendu par la classe Pushpin. Avant de continuer, vous aurez donc besoin d’un modèle qui représentera les stations sur la carte. Créez la classe Pin dans votre projet :

public class Pin
{
    public Station Station { get; set; }

    public string Label { get { return this.Station.Number.ToString(); } }

    public GeoCoordinate Location
    {
        get
        {
            return new GeoCoordinate(
                (double)this.Station.Latitude,
                (double)this.Station.Longitude);
        }
    }
}

Transformez maintenant votre collection de Stations en une collection de Pins :

private void GetStationsInRectangleCallbak(IAsyncResult result)
{
    var stations = this._repository.EndExecute<Station>(result);

    var p = from s in stations
            select new Pin { Station = s };

    Dispatcher.BeginInvoke(
        new Action<IEnumerable>((pins) => pinLayer.ItemsSource = pins), p);
}

Et un calque pour afficher le tout

Dans le code ci-dessus, nous avons transformé les stations et assigné cette nouvelle collection au calque de type MapItemsControl qui hébergera les punaises.

<map:Map x:Name="Map"
    CredentialsProvider="{StaticResource BingMapsKey}"
    ZoomBarVisibility="Visible" ZoomLevel="16"
    ViewChangeEnd="OnViewChangeEnd">
    <map:MapItemsControl x:Name="pinLayer">
        <map:MapItemsControl.ItemTemplate>
            <DataTemplate>
                <map:Pushpin Location="{Binding Location}"
                             Content="{Binding Label}"
                             Tap="OnStationTap" />
            </DataTemplate>
        </map:MapItemsControl.ItemTemplate>
    </map:MapItemsControl>
</map:Map>

MapItemsControl qui expose, entre autres, les propriétés ItemsSource et ItemTemplate qui nous permettent de spécifier les éléments à afficher et le template à utiliser pour leur rendu à l’écran, respectivement. Dans l’exemple ci-dessus, chaque punaise sera représentée par un Pushpin dont les propriétés sont liées à celles du modèle créé à l’étape précédente. De plus, la méthode OnStationTap sera appelée lorsque l’on appuie sur les repères :

private void OnStationTap(object sender, GestureEventArgs e)
{
    var station = ((sender as Pushpin).DataContext as Pin).Station;
}

Nous savons que c’est un objet de type Pushpin qui appelle la méthode et que son DataContext est de type Pin. Il ne reste plus qu’à appeler la propriété Station de ce dernier type pour obtenir les information de la station que l’utilisateur a choisi.

Lundi nous passerons cette station à une nouvelle page qui sera chargée d’afficher ses détails.

Consommation d’un service OData avec Windows Phone 7 “Mango”

Ceci est le quatrième billet d’une série sur Windows Phone 7 dans laquelle je construis une application permettant de surveiller la disponibilité de vélos des stations Vélib’ à Paris. Pour rappel, voici la table de matières:

  1. Introduction et installation des outils
  2. Création d’une application et utilisation du contrôle Bing Maps
  3. Le GPS et les services de géolocalisation
  4. Consommation d’un service OData
  5. Ajout de punaises sur une carte Bing Maps
  6. Création de nouvelles pages et navigation
  7. Création de vignettes sur la page d’accueil

OData

odataMaintenant que votre application est capable de localiser le téléphone et de centrer la carte sur sa position, il est temps de rechercher les stations Vélib’ se trouvant à proximité. Pour cela nous allons utiliser un service OData qui expose des informations sur les vélos de la ville de Paris.

Note : malheureusement, cette pratique n’est pas exactement bien vue par les fournisseurs du service, donc il est possible que dans l’avenir ces instruction ne soient plus valables.

Tout d’abord, qu’est-ce qu’OData ? Il s’agit d’un protocole ouvert pour le partage de données. Il permet d’exposer des jeux de données aux formats ATOM (XML) ou JSON se basant sur une architecture REST. Je ne rentrerai pas dans les détails, mais je vous laisserai visiter le site officiel si vous voulez en savoir plus.

J’ai choisi une source de données OData parce qu’il s’agit d’un protocole léger et facile à consommer, notamment avec l’inclusion dans les Windows Phone Developer Tools 7.1, que je vais continuer à appeler les outils “Mango”, d’un client OData.

Le client OData

Commençons donc par ajouter une référence au service OData :

Add Service Reference

Voilà, c’est fini !

Stations Vélib’ à proximité

Le client en place, il ne reste plus qu’à récupérer les stations Vélib’ à proximité de l’utilisateur.

Si vous regardez la description du service OData de près :

<FunctionImport Name="GetStationsInRectangle" EntitySet="Stations"
                ReturnType="Collection(UnVelo.Station)" m:HttpMethod="GET">
  <Parameter Name="point1" Type="Edm.String" Mode="In" />
  <Parameter Name="point2" Type="Edm.String" Mode="In" />
</FunctionImport>

Vous remarquerez la présence d’une fonction qui retourne les stations présentes dans un rectangle. Ce rectangle est défini par deux points : le coin nord-ouest et le coin sud-est.

Comme nous souhaitons récupérer la liste de stations lorsque la carte affichée change (déplacement, changement de zoom), vous allez vous abonner à l’évènement ViewChangeEnd, qui sera déclenché une fois que le déplacement ou le changement de zoom est fini :

<map:Map x:Name="Map"
    CredentialsProvider="{StaticResource BingMapsKey}"
    ZoomBarVisibility="Visible" ZoomLevel="17"
    ViewChangeEnd="OnViewChangeEnd" />

Dans le gestionnaire de l’évènement, vous allez utiliser un StationRepository qui a été créé automatiquement par Visual Studio à l’étape précédente, pour lancer un appel asynchrone sur la fonction GetStationsInRectangle.

private readonly string GetStationsInRectangleTemplate = "GetStationsInRectangle?point1='{0}'&point2='{1}'";

private GeoCoordinateWatcher _gcw;
private StationRepository _repository;

public MainPage()
{
    InitializeComponent();

    this._gcw = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
    this._gcw.MovementThreshold = 20;
    this._gcw.PositionChanged += this.OnPositionChanged;

    this._repository = new StationRepository(new Uri("http://unvelo.fr/api/v1/"));

    this.Loaded += this.OnPageLoaded;
}

private void OnViewChangeEnd(object sender, MapEventArgs e)
{
    this._repository.BeginExecute<Station>(
        new Uri(
            string.Format(GetStationsInRectangleTemplate, Map.BoundingRectangle.Northwest, Map.BoundingRectangle.Southeast),
            UriKind.Relative),
        this.GetStationsInRectangleCallbak,
        null);
}

Le client OData créé par Visual Studio supporte uniquement les appels asynchrones dans le but d’éviter des exécutions d’appels longs sur le thread de l’interface graphique, étant donné que ceci dégraderait l’expérience utilisateur. Vous devrez donc créer une méthode callback qui sera appelée à la fin de l’exécution asynchrone pour traiter le résultat de celle-ci :

private void GetStationsInRectangleCallbak(IAsyncResult result)
{
    var stations = this._repository.EndExecute<Station>(result);
}

Vous pouvez vérifier que des stations sont effectivement retournées grâce au débuggeur de Visual Studio. Demain nous les convertirons en punaises à afficher sur la carte. D’ici là, vous avez des données avec lesquelles vous pouvez vous amuser. Si vous avez un peu d’expérience avec Silverlight ou WPF, n’hésitez pas à essayer d’afficher ces données par binding sur différents contrôles.