Browsed by
Category: Windows Phone 7

Comment charger proprement une page web sans cache ?

Comment charger proprement une page web sans cache ?

Une grande majorité des développeurs Windows Phone ont surement déjà rencontré ce problème : On souhaite requêter une page web, sauf que c’est une version provenant du cache que l’on nous retourne.

Un hack très répondu et à mon sens, pas propre, est d’ajouter un paramètre variable à l’Uri de sa requête comme par exemple :


var request = WebRequest.CreateHttp("<a href="http://www.feelmygeek.com/rand.php?s">http://www.rudyhuyn.com/?rand="+new</a> Random().Next());

ou encore


var request = WebRequest.CreateHttp("<a href="http://www.feelmygeek.com/rand.php?s">http://www.rudyhuyn.com/?rand="+DateTime.Now.Ticks</a>);

Personnellement, je ne trouve pas ça élégant, on est assez proche de MacGyver qui souhaite réparer sa voiture grâce à un trombone.

Le protocole de test

Pour effectuer mes tests, j’ai développé un petit script php:


<?php

header("Cache-Control: max-age=31536000");

header("Expires: Sun, 27 Oct 2013 14:50:11 GMT");

echo rand() . "n";

echo rand() . "n";

echo time();

?>

 

et un client Windows Phone :


var request = WebRequest.CreateHttp("http://www.feelmygeek.com/rand.php");
request.BeginGetResponse((iar) =>{
var response=request.EndGetResponse(iar).GetResponseStream();
var val = new StreamReader(response).ReadToEnd();
Deployment.Current.Dispatcher.BeginInvoke(() => {
MessageBox.Show(val);
});
}, null);

 

Si deux requêtes consécutifs retourne le même résultat, on pourra donc en déduire que le cache a été utilisé.

Alors comment le faire élégamment ?

 Cache-Control :no-cache ?

Ajoutons donc  la ligne suivante à notre test :


request.Headers[HttpRequestHeader.CacheControl] = "no-cache";

Logiquement, cela devrait fonctionner, mais… non, le message affiché est bien toujours le même, il faut donc trouver une autre solution.

Cache-control : max-age=0 ?


request.Headers[HttpRequestHeader.CacheControl] = "max-age=0";

Non plus… de toute évidence, Windows Phone ignore cette instruction.

Contournons donc le problème

Vu que cache-control ne semble pas pris en compte, trouvons une autre solution.

Au lieu de dire “n’utilise pas le cache”, nous allons plutôt dire, “retourne moi une nouvelle page si elle a été modifiée depuis 1970”.

Sachant qu’internet a été inventé en 1973, on devrait être tranquille.

Voici comment le faire :


request.Headers[HttpRequestHeader.IfModifiedSince] = DateTime.MinValue.ToString();

Note :

Si vous cherchez bien sur internet, vous trouverez probablement ce genre de solution :


request.Headers[HttpRequestHeader.IfModifiedSince] = DateTime.UtcNow.ToString();

Cette solution est a éviter et à bannir. Pour peu que votre serveur gère correctement le header http IfModifiedSince, il vous retournera très probablement un code 304 (not modified) car littéralement vous lui demandez :

Retourne moi la page, uniquement si elle a été modifié entre maintenant et maintenant

Ce qui n’est pas le plus efficace.

Conclusion

Si vous souhaitez éviter tout problème de cache, voici donc la méthode la plus élégante pour cela :


var request = WebRequest.CreateHttp("http://www.feelmygeek.com/rand.php");
request.Headers[HttpRequestHeader.IfModifiedSince] = DateTime.MinValue.ToString();
request.Headers[HttpRequestHeader.CacheControl] = "no-cache";
request.BeginGetResponse((iar) =>{
var response=request.EndGetResponse(iar).GetResponseStream();
var val = new StreamReader(response).ReadToEnd();
Deployment.Current.Dispatcher.BeginInvoke(() => {
MessageBox.Show(val);
});
}, null);

 

Un dernier point : pourquoi avoir laissé “CacheControl : no-cache” ?

Tout simplement pour éviter que des proxys vous retourne une ancienne version de la page entre le téléphone et le serveur !

Et nos amis de Windows 8 ?

Une petite note pour nos amis WinRT, HttpWebRequest dispose d’une propriété IfModifiedSince de type DateTime, sauf que ma solution ne fonctionne pas avec eux car comme l’indique la documentation :

Si la propriété IfModifiedSince a la valeur DateTime.MinValue, l’en-tête HTTP If-Modified-Since est supprimé de la propriété Headers et de WebHeaderCollection.

La solution est donc de contourner tout cela en écrivant :


request.IfModifiedSince = DateTime.MinValue.AddSecond(1);

Voilà !

Générer une image pour le fond d'une tuile

Générer une image pour le fond d'une tuile

Nous allons dans cet article reprendre le projet de l’article précédent pour le compléter afin qu’il génère lui même le fond de sa tuile en incrustant dans l’image de fond : un label et l’heure courante.

Nous avons découpé notre application en trois projets :

  • l’application en même
  • le background agent
  • la libraire commune contenant notamment la fonction de génération de tuile.
Pour modifier la génération, nous n’allons qu’éditer le troisième projet, et plus particulièrement la fonction :
public static StandardTileData GenerateTile()

Création de l’image

Pour créer notre image, nous allons utiliser la classe WriteableBitmap et plus particulièrement sa fonction Render qui permet de faire le rendu d’un contrôle XAML directement dans l’image au lieu de l’écran.

Nous allons donc créer deux TextBlock, le premier contenant le label “heure:”, le seconc contenant l’heure courante.

Commençons par créer la police et la brush pour nos textblocks :

var fontFamily = new FontFamily("Segoe WP SemiLight");
var fontColor = new SolidColorBrush(Colors.White);

Créons maintenant nos deux textblocks :

//label
var textTextBlock = new TextBlock()
{
Text = "time:",
FontSize = 40,
Foreground = fontColor,
FontFamily = fontFamily
};

//time textblock
var timeTextBlock = new TextBlock()
{
Text = DateTime.Now.ToShortTimeString(),
FontSize = 20,
Foreground = fontColor,
FontFamily = fontFamily,
TextWrapping = TextWrapping.Wrap,
Width = 173
};

il nous reste maintenant qu’à créer notre writeableBitmap et d’y dessiner nos deux textblocks. La fonction Render prenant comme deuxième paramètre une transformation, nous allons nous en servir pour positionner nos contrôles via une TranslationTransform.

var bitmap = new WriteableBitmap(173, 173);

//render the label
bitmap.Render(textTextBlock, new TranslateTransform()
{
X = 0,
Y = 16
});

//render the time
bitmap.Render(timeTextBlock, new TranslateTransform()
{
X = 0,
Y = 55
});
//permet de forcer le dessin
bitmap.Invalidate();

Reste à sauvegarder notre image dans l’isolated Storage de notre application. Attention toutefois, nous ne pouvons les sauvegarder n’importe ou, il faut le faire dans le dossier “/Shared/ShellContent” qui permet de partager du contenu entre l’agent et l’application.

using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
var stream = store.CreateFile(tileImage);
bitmap.SaveJpeg(stream, 173, 173, 0, 100);
stream.Close();
}

Voici le résultat :

Bon, le texte est bien affiché, mais le fond de la tuile est noir (si on met le thème noir, le fond est toujours noir) et non de la couleur du téléphone.

En fait, le writeableBitmap ne peut être sauvegardé qu’en JPG, donc dans un format de fichier sans transparence. Par défaut, le WriteableBitmap étant tout noir, voilà pourquoi notre tuile est ainsi.

Il n’est pas possible de générer des PNG, toutefois, il est possible de générer des JPG ayant comme fond la couleur d’accent courante. Attention toutefois, comme nous l’avons pu noter dans l’article Les différentes solutions pour dessiner dans une tuile, si l’utilisateur change sa couleur de fond, la tuile garder la précédente couleur jusqu’au prochain refresh (lancement de l’application ou background agent).

Pour remplir le fond, il faut déjà créer un rectangle avec cette couleur :

var backgroundRectangle = new Rectangle() { Height = 173, Width = 173, Fill = (Brush)Application.Current.Resources["PhoneAccentBrush"] };

puis juste avant de dessiner les textblock, on dessine le rectangle :

bitmap.Render(backgroundRectangle, new TranslateTransform());

On recompile, on relance l’application et voici le résultat :

Attention au contexte !

Un point important, est le contexte, Textblock, Rectangle et WriteableBitmap nécessite d’être dans le thread UI pour fonctionner, sinon une exception “Invalid cross-thread access” est lancée.

Du côté de notre application pas de soucis, App_Desactivate et App_Closing sont bien appelé dans le thread UI, toutefois, le background Agent par défaut n’est pas dans le thread UI, il faut donc forcer le passage sur ce thread en entourant l’instruction UpdateTiles de l’agent de :

            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                CustomTile.TileGenerator.UpdateTiles();
            });

Téléchargez la solution complète : CustomTile ZIP

Les différentes solutions pour dessiner dans une tuile

Les différentes solutions pour dessiner dans une tuile

Pour personnaliser une tuile, nous avons accès au niveau texte :
– le titre (Title)
– le titre arrière (BackTitle)
– le compteur sur la face avant(Count)
– la description, un texte écrit en gros caractère sur la face arrière (BackContent)

Imaginons maintenant que je souhaite afficher l’heure et un texte tout en gardant le titre sur la face avant, ceci m’est pas possible avec les propriétés précédentes.

Toutefois, ayant la possibilité de modifier les images de fond de chaque côté de la tuile, je peux générer une image contenant le texte que je souhaite afficher et l’appliquer en tant que fond de la tuile.

Deux possibilités s’offrent à nous.

La génération via un serveur web

Dans cette solution, on développe un service web (en apache ou asp.net) qui a partir des paramètres de l’uri, retourne une image PNG contenant ces informations.

Avantages

  • on peut générer des PNG transparent permettant notamment de faire des tuiles utilisant la couleur accent du téléphone
  • on peut modifier le design de la tuile sans mettre à jour l’application
  • plus rapide pour le téléphone, n’oublions pas qu’un background agent ne dispose que de 25 secondes pour faire ses tâches.

Inconvénients

  • nécessite un serveur web : coût financier et humain (pour son administration)
  • utilise la bande passante de l’utilisateur
  • la tuile ne se mettra pas à jour si le téléphone ne dispose pas réseau au moment du réveil de l’agent.

La génération de l’image par l’agent/l’application

Dans cette solution, nous demandons à l’application de générer elle même l’image et de la stocker dans l’isolated Storage.

Avantages

  • ne nécessite pas un serveur web
  • n’utilise pas la bande passante
  • fonctionne même sans réseau

Inconvénients

  • on ne peut générer que des JPG, il est possible d’utiliser la couleur accent dans le jpeg, mais si l’utilisateur la change, la tuile gardera la précédente couleur jusqu’au prochain réveil de l’agent
  • prends plus de temps que les autres solutions
  • impossible de modifier le design de la tuile sans mettre à jour l’application

Solution alternative : utilisation d’une collection d’image

Si on n’a besoin de générer qu’un nombre faible de variante pour l’image de fond, par exemple : une application affichant sur sa tuile uniquement un chiffre entre 1 et 9 ou encore une application affichant sur sa tuile uniquement un nuage/soleil/pluie.

Dans ce cas, il n’est pas forcément nécessaire d’utiliser un serveur ou de générer une image, on peut embarquer dans l’application (en Content) l’ensemble des variantes de la tuile et référencer la bonne tuile directement :

 

 new StandardTileData()
            {
                Title = "title",
                BackgroundImage=new Uri("/Tiles/Sun.png",UriKind.Relative)
            };

Avantages

    li>on peut utiliser des PNG transparents permettant notamment de faire des tuiles utilisant la couleur accent du téléphone
  • ne nécessite pas un serveur web
  • n’utilise pas la bande passante
  • rapide
  • fonctionne même sans réseau
  • plus rapide pour le téléphone, n’oublions pas qu’un background agent ne dispose que de 25 secondes pour faire ses tâches.

Inconvénients

  • alourdi le XAP
  • pas adapté à des tuiles très dynamiques
  • impossible de modifier le design de la tuile sans mettre à jour l’application
Créer un agent périodique qui modifie la tuile

Créer un agent périodique qui modifie la tuile

Jusqu’à maintenant, pour mettre à jour une tuile, il fallait obligatoirement posséder un serveur web qui via le push notification, demandait au téléphone de mettre à jour la tuile.

Grâce à mango et à l’ajout des scheduled agents, ce serveur n’est plus forcément obligatoire. Nous pouvons maintenant créer un agent (une tâche de fond qui va s’exécuter 25 secondes toutes les demi heures (environ)) qui va récupérer des informations et générer une nouvelle tuile à partir de ces informations.

Si vous ne savez pas comment créer une tuile additionnelle, lisez cet article http://www.rudyhuyn.com/blog/2011/05/24/comment-ajouter-des-tuiles-additionnelles-a-son-application/

Création de l’agent

Nous allons commencer par créer notre agent, cela se fait de façon très simple.

Sous visual, sélectionnez la solution, faites un clic droit et sélectionner “ajouter > créer un nouveau projet” :

Sélectionnez maintenant un projet de type “Windows Phone Scheduled Task Agent”

et validez.

Vous avez maintenant deux projets dans votre solution, un correspondant à votre application et un correspondant à la tâche qui sera appelé toutes les 30 minutes. Avant d’aller plus loin, il faut lier les deux projets. Sélectionnez votre projet principal, faites un clic droit sur “references” et sélectionnez dans l’onglet “projets” le projet correspondant à votre agent.

Sans vous en rendre compte, Visual à modifié le fichier WMAppManifest de votre projet afin d’ajouter la référence vers votre agent :

<Tasks>
<DefaultTask Name="_default" NavigationPage="MainPage.xaml" />
<ExtendedTask Name="BackgroundTask">
<BackgroundServiceAgent Specifier="ScheduledTaskAgent" Name="MyScheduledTaskAgent" Source="MyScheduledTaskAgent" Type="MyScheduledTaskAgent.ScheduledAgent" />
</ExtendedTask>
</Tasks>

Il suffit maintenant de démarrer l’agent, mais avant cela, il faut savoir que pour être validé, une application doit permettre à l’utilisateur de démarrer ou stopper les agents à sa guise, nous allons donc ajouter un togglebutton dans ce but :


 

private void ToggleButton_Click(object sender, System.Windows.RoutedEventArgs e)
{

string name="MyScheduledTaskAgent";
if (!((ToggleButton)sender).IsChecked.Value)
{
...//désactiver l'agent
}
else
{
...//activer l'agent
}
}

La variable “Name” représente ici le nom de votre tâche (le nom du projet sauf si vous l’avez modifié).

Il nous reste à compléter le code.

Pour supprimer un agent, il suffit de le rechercher et si on le trouve, alors on demande au service SchedultedAction de le supprimer de sa liste

var periodicTask = ScheduledActionService.Find(name) as PeriodicTask;
if (periodicTask != null)
ScheduledActionService.Remove(name);

De la même façon, pour activer un agent, on commence par vérifier qu’il n’existe pas, s’il existe déjà, alors on le supprime, il nous reste alors à le créer via une PeriodicTask et de l’ajouter au service ScheduledAction.

var periodicTask = ScheduledActionService.Find(name) as PeriodicTask;
if (periodicTask != null)
ScheduledActionService.Remove(name);

periodicTask = new PeriodicTask(name) { Description="this is a test agent"};
ScheduledActionService.Add(periodicTask);

Dernière chose, il faut initialiser la valeur IsChecked de notre bouton au chargement de la page, en écrivant dans le constructeur :

var periodicTask = ScheduledActionService.Find(AgentName) as PeriodicTask;
ToggleAgent.IsChecked = periodicTask != null;

Maintenant que nous avons mis en place notre agent, nous allons lui demander de mettre à jour la tuile de notre application. Il y a deux écoles à ce sujet : tout mettre dans le projet correspondant à l’agent, ou créer une troisième librairie contenant les fonctionnalités communes entre l’application et l’agent, comme notamment la fonction générant la tuile.

Personnellement, je préfère la 2ème méthode que je trouve plus propre.

Créons donc un troisième projet de type “librairie de classe” et ajoutons le comme référence aux deux autres projets (application et agent).

Créons une classe nommée TileGenerator et ajoutons une méthode

public static StandardTileData GenerateTile()

Dans cette méthode nous allons créer le contenu de la tuile. Nous allons créer une tuile très simple avec uniquement un titre et l’heure courante au dos de la tuile afin de valider la mise à jour. Dans un article à suivre, nous créerons un vrai contenu pour cette tuile en générant nous même les images de celle-ci.

public static StandardTileData GenerateTile()
{
return new StandardTileData()
{

Title="test time",
BackContent=DateTime.Now.ToShortTimeString()
}
}

Modifions maintenant l’agent pour qu’il mette à jour la tuile :

public class ScheduledAgent : ScheduledTaskAgent
{
protected override void OnInvoke(ScheduledTask task)
{

var tile = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString() == "/MainPage.xaml");
tile.Update(CustomTile.TileGenerator.GenerateTile());
NotifyComplete();
}
}

Mettre à jour la tuile quand on sort de l’application

Un dernier point, lorsque l’on est dans l’application et qu’on en sort, pourquoi pas en profiter pour mettre à jour la tuile sans attendre que l’agent s’exécute (dans 30 minutes).

Il suffit donc dans le fichier app.xaml.cs de reprendre le code que l’on a utilisé dans l’agent, mais pour éviter la redondance de code, nous allons externaliser la fonction de mise à jour des tuiles dans la librairie commune :

      public static void UpdateTiles()
        {
            var tile = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString() == "/MainPage.xaml");
            tile.Update(CustomTile.TileGenerator.GenerateTile());
        }

 

Téléchargez le code source du projet : CustomTile

Tester l'apparence de son application sur le marketplace

Tester l'apparence de son application sur le marketplace

Lorsque l’on soumet son application, il est parfois assez difficile d’imaginer à quoi elle va ressembler une fois sur le marketplace. Par exemple, est ce que mon “Background art” est adapté au marketplace ?

Je me suis posé cette question ce WE, en voyant Fuse en ‘application du jour’ sur le marketplace, plutôt cool, mais le ‘background art’ que j’avais créé pour l’application ne rendait pas bien du tout, trop sombre. Une des mes applications avaient aussi un petit soucis esthétique car sa “short description” était de quelques pixels trop long pour le marketplace, la dernière lettre étant alors découpé.

Face à ce constat, j’ai donc décidé de créer un faux marketplace où il sera possible de tester et vérifier ses background arts, si le nom de notre application ou sa petite description ne sont pas découpé, etc…

J’ai donc profité du WE et que Fuse était application du jour pour reproduire le marketplace au pixel près et avec exactement le même comportement (par exemple la taille de la police pour l’application du jour qui change selon la taille du texte). En développant l’application je me suis ainsi rendu compte que le background art était affiché avec une opacité de 0.4, or le background art que j’avais soumis était déjà sombre, donc au final il était difficile à distinguer.

Télécharger Fake Marketplace

Fake Marketplace est téléchargeable avec ses sources sur codeplex, à l’adresse suivante : http://fakemarketplace.codeplex.com/

 

Comment l’utiliser ?

Pour utiliser Fake Marketplace, c’est plutôt très simple, il suffit de lancer la solution, les seuls données à modifier se trouve dans le répertoire MyApp :

Vous y trouverez :

  •  BackgroundArt.png : le background art de votre application (PNG 1000*800), c’est le fond qui sera affiché si votre application est “application du jour”
  • Tile.png : représente l’image de votre application, visible dans l’ensemble du marketplace
  • MyAppData.resx : un fichier ressource contenant toutes les informations relatives à votre application

Voyons plus en détail le fichier MyAppData

  • Author : votre nom
  • Description : la description de votre application (visible sur la fiche de votre application)
  • ShortDescription : le sous titre de votre application, visible notamment sur la home quand elle apparait dans les listes ‘top’, ‘new’ ‘featured’
  • Title : le nom de votre application
Une fois que vous avez modifié ces paramètres et modifié les images tile.png et backgroundart.png, il vous suffit simplement de lancer la solution.

 

 

 

 

Comment tester le tombstoning avec un téléphone mango ?

Comment tester le tombstoning avec un téléphone mango ?

Mango a apporté le fast-resume, c’est à dire que le téléphone garde en mémoire votre application lorsque vous la quittez (en appuyant sur la touche windows par exemple) afin de pouvoir la réafficher le plus rapidement possible lorsque vous reviendrez dessus.

Toutefois il faut continuer à penser au tombstoning (c’est à dire la sauvegarde d’un contexte et la suppression du processus), car malgré l’ajout du fast-resume, si trop d’applications sont ouvertes, alors le système va passer les applications les plus anciennes en tombstoning, voici un petit rappel du cycle de vie d’une application Windows Phone :

 

Si on compare au cycle de vie de 7.0, on voit clairement que l’état “Dormant” a été intercalé entre le desactivate et le tombstoned, il va permette pour résumer de retarder au maximum le tombstoning afin de pouvoir récupérer l’application plus rapidement.

Si l’on sort de son application et que l’on fait précédent, on ne va donc pas passer par le tombstoning, pour cela il faudrait lancer 4-5 applications supplémentaire afin que le système passe notre application que l’on essaie de déboguer en tombstoning, ce qui peut être très laborieux au final.

Comment tester le tombstoning alors ?

Pour éviter le fast-resume et afin de deboguer le tombstoning, il suffit simplement d’aller dans les propriétés du projet, d’ouvrir l’onglet “debug” et de cocher la case : “Tombstone upon desactivation while debugging”.

Maintenant en sortant de l’application, l’application sera mise automatiquement en tombstoning, vous pourrez alors tester que la sauvegarde de votre contexte se déroule correctement.

Accéder aux cookies du webbrowser de votre application

Accéder aux cookies du webbrowser de votre application

Lorsque votre application contient un contrôle de type WebBrowser, il peut parfois être nécessaire d’accéder aux cookies de ce dernier. Malheureusement ceci était impossible avec Windows Phone 7.0, mais maintenant possible avec le nouveau SDK 7.1 (pour Windows Phone 7.5 ou ‘Mango’).

WebBrowserExtension

Mango apporte donc une nouvelle classe nommée : WebBrowserExtension (voir sur la MSDN), qui expose notamment une méthode GetCookies qui retourne une collection de cookie.

La méthode prend en paramètre un contrôle de type WebBrowser, il est donc possible d’accéder aux cookies d’un WebBrowser parmi d’autres sans soucis.

var cookies = WebBrowserExtensions.GetCookies(MyWebBrowser);

foreach (Cookie cookie in cookies)
{
...
}

Usage

Un des usages qui peut être intéressant est de récupérer les cookies pour ensuite s’en servir dans une HttpWebRequest. On peut par exemple demander à un utilisateur de se connecter à un site, récupérer les cookies et ensuite les utiliser pour appeler d’autres pages du site sans passer par le navigateur.

Par exemple :

 HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://www.contoso.com");
      req.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705;)";
      req.Method = "POST";
      req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
      req.Headers.Add("Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7");
      req.KeepAlive = true;
      req.AllowAutoRedirect = false;
      req.CookieContainer = WebBrowserExtensions.GetCookies(MyWebBrowser);

Nous avons un accès en lecture seule aux cookies, il est impossible d’en injecter, d’en modifier ou d’en supprimer.

De plus, nous n’avons accès qu’aux cookies de la page courante et non à l’ensemble des cookies !

A quel niveau sont stocké les cookies ?

On pourrait se poser la question de comment Windows Phone gère les cookies au sein d’une application. On pourrait par exemple se demander que se passe t’il si j’ai deux webbrowser sur une même page, partagent t’ils les cookies ou ont ils chacun leurs stockages ? La question est légitime car pourquoi devoir passer un webbrowser en paramètre de la fonction GetCookie ?

En réalité, c’est l’application qui porte les cookies, donc si j’ai plusieurs webbrowser, ils vont tous se partager le même contexte, comme internet explorer et ses onglets par exemple. De plus, l’application va sauvegarder les cookies, ainsi, si je sors de l’application et que je la relance, ils seront toujours là.

Enfin pour répondre à la question de savoir pourquoi passer le webbrowser en paramètre, c’est assez simple : comme on l’a dit précédemment, seule les cookies de la page courante sont retournés, donc en passant le webbrowser, la fonction va pouvoir identifier quel cookie elle doit retourner.

A savoir, si j’ouvre deux webbrowsers sur le site facebook par exemple et que je m’identifie sur l’un d’entre eux, en demandant les cookies du second, je vais récupérer aussi les cookies généré suite à l’identification, preuve du partage de mémoire entre les deux navigateurs.

Attention

Une exception peut être levé parfois lors de l’appel à la fonction GetCookies, c’est le cas par exemple lorsque l’on navigue vers le site http://www.bing.com à cause d’un cookie qu’il interprète mal, du moins avec la version 7712 de mango (beta 2 refresh):

The ‘Name’=’_HOP;_SS’ part of the cookie is invalid

 

Télécharger le projet exemple

TestWebbrowserExt

Edit : Problème de sécurité ?

Suite à la publication de cet article, j’ai eu rapidement des questions sur les risques de sécurité, en effet, si une application peut accéder à mes cookies, elle pourra savoir sur quel site je suis allé, publier des informations facebook/twitter, etc…

En fait non, chaque application est sandboxé, c’est à dire qu’un WebBrowser dans une application n’a pas accès aux cookies d’une autre, Internet Explorer compris. Ainsi, si je suis connecté à Facebook sur IE9, le webbrowser dans une autre application n’aura pas accès à ses cookies et donc, ne pourra se connecter elle aussi à facebook.

Comment supprimer le verso d'une tuile

Comment supprimer le verso d'une tuile

Introduction

Sous mango, il est très facile de créer une tuile ayant deux faces avec au recto : 

  • un titre
  • un compteur
  • un fond
et au verso
  • un titre
  • un texte
  • un fond
Voici un exemple montrant comment on créé une tuile :
var newtile = new StandardTileData()
{
Title = "Fuse",
Count = 2,
BackgroundImage = uriBackground,
BackTitle ="engadget",
BackContent="resumé de l'article",
BackBackgroundImage= uriBackground2
};
ShellTile.Create(new Uri("/MainPage.xaml?id=" + Id, UriKind.Relative), newtile);
Pour plus d’informations, lire l’article précédent.
Que l’on souhaite mettre à jour ou supprimer une tuile, la principale difficulté est de retrouver la bonne tuile. Pour cela, le seul moyen est d’analyser la propriété NavigationUri  et d’en déduire le rôle de cette tuile. Lire l’article précédent pour plus d’information.
var shell = ShellTile.ActiveTiles.FirstOrDefault((s) => s.NavigationUri.OriginalString == "/MainPage.xaml?id=" + Id);

if(shell!=null)
{
shell.Update(...);
}

Suppression du verso

Si nous récupérons une tuile ayant déjà un verso et que l’on exécute le code suivant :


var newtile= new StandardTileData()
{
Title = "Fuse update",
Count = 12,
BackgroundImage = new Uri("img/CC.jpg", UriKind.Relative)
};

shell.Update(newtile);

On pourrait imaginer que la tuile n’ait plus qu’une seule face, mais malheureusement ce n’est pas le cas, elle continue à afficher régulièrement l’arrière de la tuile comme auparavant.

Pourquoi ?

En fait, il ne faut pas imaginer StandardTileData comme un objet, mais plutôt comme un structure de données représentant les données à modifier, et la fonction Update ne sort pas à remplacer la tuile, mais à la mettre à jour. Ainsi, la fonction Update en réalité, regarde toutes les propriétés de l’object StandardTileDate et si leur valeur n’est pas null, alors il demande une mise à jour de la tuile.

Dans notre exemple précédent, on n’a pas donné de valeurs aux propriétés BackTitle, BackContent et BackBackground, la fonction update va donc les ignorer et va garder les anciennes valeurs. C’est donc pour cela que la tuile continue à afficher l’ancien verso.

Solution

Pour supprimer le verso, il faut donc dire à la tuile que les trois propriétés représentant le verso soit réinitialisé.

Pour BackContent et BackTitle, représenté par des strings, il suffit de leurs affecter la valeur String.Empty. Attention, leurs affecter la valeur null, ne fera rien et gardera l’ancienne valeur.

Pour le BackBackground, de type Uri, cela se complique un peu. Comme pour les deux propriétés précédentes, la mettre à null ne fera rien, mais pour autant il n’existe pas de constante Uri.Empty comme pour les strings.

Si on écrit :


new Uri(null);

Le programme  va lancer une exception de type ArgumentNullException, de même :


new Uri(String.Empty);

va lancer une exception de type UriFormatException.

En fait, il ne va pas arriver à savoir si l’uri est relative ou absolue et sera donc perdu. Il suffit donc de lui préciser que l’uri est de type absolu pour que tout fonctionne !

Par conséquent, pour supprimer le verso d’une tuile, il suffit d’écrire :

var newtile = new StandardTileData()
{
Title = "Fuse",
Count = 2,
BackgroundImage = uriBackground,
BackTitle =String.Empty,
BackContent=String.Empty,
BackBackgroundImage= new Uri(String.Empty,UriKind.Relative)
};
shell.Update(newtile);

Bon dev !
Génération automatique de QR-Codes avec Windows Phone

Génération automatique de QR-Codes avec Windows Phone

Je viens de mettre à disposition sur codeplex une librairie que j’avais codé pour l’application Fuse, permettant de généré des QR-Code en 2 lignes de codes. Nous allons donc voir comment l’utiliser :

Après avoir référencé la dll disponible ici : http://qrcodegenerator.codeplex.com/ (code source + exemple)

Il suffit d’écrire :


var generator=new QRCodeGenerator();

QRCodeImage.Source=generator.Generate("ceci est mon texte");

QRCodeImage représentant un contrôle silverlight Image.

Les propriétés

EncodeMode

Cette propriété représente le type des données que vous souhaitez stocker dans le QR Code.

Les valeurs sont :

  • ALPHA_NUMERIC : seulement des chiffres et des lettres (sans Romechko). Attention, seuls les lettres a-zA-Z0-9 sont prises en compte, impossible donc d’utiliser les accents ou les symboles (max 7089 caractères)
  • NUMERIC : seulement des nombres (max  4296 caractères)
  • BYTE : des données binaires (max 2953 bytes)
En règle général, on utilise le type BYTE pour stocker des uri ou du texte.
La valeur par défaut est BYTE.

BackgroundColor et ForegroundColor

Par défaut noir et blanc, il est toutefois possible de modifier la couleur du QR-Code, pensez juste à avoir des couleurs qui se différencient bien pour une meilleure reconnaissance.

Version

La version d’un QRCode correspond en fait au nombre de carré visible sur une ligne ou une colonne. Plus il y a de ‘carré’, plus on pourra stocker de l’information et inversement plus il sera compliqué à lire.

Par exemple, un QR Code version 1 (21 carrés de côté) ne pourra stocker que  17 octets alors qu’un QR Code version 40 (177 carrés de côté) pourra stocker 1817 octets.

Un très bon site pour voir les limites de chaque version : http://www.denso-wave.com/qrcode/vertable1-e.html

Par défaut, la version est 0, on laisse donc la librairie trouver la plus petite version pouvant accueillir nos données. C’est l’idéal pour avoir un QR Code le plus facilement lisible.

ErrorCorrect

Parce que la reconnaissance n’est pas toujours parfaite, QR Code intègre de la redondance d’information afin  de pouvoir lire le QR Code même s’il n’est pas totalement visible. (La redondance utilise le code Reed-Solomon pour les curieux)

Néanmoins, plus le taux d’erreur sera haut, moins on pourra stocker de données car la redondance prendra plus de place. Voila un exemple avec une QR Code version 7 :

  • L : 1248 bits max (environ 7% de redondance)
  • M : 992 bits max (environ 15% de redondance)
  • Q : 704 bits max (environ 25% de redondance)
  • H : 528 bits max (environ 30% de redondance)
Pour un usage mobile, la correction M sera suffisante.

Scale

Scale représente le nombre de pixel que représente un la largeur d’un petit carré. Par défaut la propriété vaut  4.

Bonne utilisation !

Les différences entre l'environnement 7.0 et 7.5

Les différences entre l'environnement 7.0 et 7.5

Je ne vais pas détailler ici la différence entre les deux SDK mais plutôt les différences que l’on peut rencontrer lorsque l’on exécute un même XAP compilé pour 7.0 sur les deux plateformes 7.0 et 7.5

Possibilité de modifier le Referer d’une requête internet

Si vous développez des applications 7.0 et que vous les testez avec un téléphone mango, faites attention ! En plus de IE9 et IE7 qui seront différent, il y a d’autres subtilités qui vous donneront de joli exception, par exemple :

webRequest.Headers[HttpRequestHeader.Referer]="http://www.bing.com/";

passe sur un téléphone mango mais pas sur un téléphone nodo pour une appli 7.0.

Le slider

Sur un téléphone 7.5, le slider ne va pas s’afficher de la même façon que sur un téléphone 7.0.

En effet, sous 7.5 un petit rectangle blanc (un thumb) est ajouté permettant de le manipuler plus facilement.

La navigation locale d’un webBrowser

Lorsque l’on lance une navigation locale (NavigateToString), sous une application 7.0 et que l’on s’enregistre sur l’évènement Navigated ou LoadCompleted, e.Uri.OriginalString vaudra null alors que sur un téléphone 7.5, la même app en 7.0 aura e.Uri.OriginalString==String.Empty.

Par conséquent, pour différencier une navigation locale d’une navigation web, il faut écrire :

String.IsNullOrEmpty(e.Uri.OriginalString)

Conclusion

Donc si vous publiez pour 7.0, essayez impérativement votre application sur un téléphone 7.0