D'après Slashdot, la version 11 de DirectX, qui pourrait arriver à la fin de cette année, supportera le rendu en mode raytracing en plus de l'habituelle rasterization.
Truc de ouf, j'trouve (ou serait-ce un poisson d'avril ?).
17:32 » Tests de site web avec Internet Explorer 6 - programmation
Comment faire pour tester un site web sous Internet Explorer 6 lorsqu'on a la version 7 d'installée ?
J'ai bien croisé une solution pour installer plusieurs versions du navigateur sur la même machine, mais elle ne me tentait guère, et surtout elle ne fonctionne pas sous Vista (OS sous lequel j'ai la joie et l'honneur de travailler chaque jour au bureau).
Heureusement, mère virtualisation vient à la rescousse des développeurs désespérés que nous sommes : en effet, Microsoft a mis à notre disposition des images de Windows XP SP2 et Vista avec au choix Internet Explorer 6, 7 ou 8 d'installé.
Vous aurez également besoin de Virtual PC (qui est gratuit) pour faire fonctionner les bestioles.
Attention, les images expirent le 3 juillet de cette année (pas de panique, elles seront remplacées par d'autres avant cette date, mais il faudra penser à les mettre à jour).
15:37 » Le code dont VOUS êtes le coupable - programmation
Je suis assez d'accord avec ce que raconte Jeff Atwood dans un de ses derniers posts.
Pour les anglophobes et ceux qui n'ont pas envie de le lire, voici un résumé : quand vous butez sur un problème de programmation, aussi tordu soit-il, n'oubliez jamais que c'est toujours de votre faute. Toujours (ou presque). Ce n'est pas la faute du compilateur, ni celle de votre IDE, encore moins celle de l'OS et probablement pas non plus celle des bibliothèques que vous utilisez. Non non, dans l'écrasante majorité des cas, c'est vous qui avez fait une bêtise.
Et c'est d'ailleurs un peu pour ça que je ne vois pas forcément d'un très bon oeil la mise à disposition des sources du framework .NET. Ce n'est pas une mauvaise chose en soi (en bon écureuil, si on me tends une noisette, je la prends), mais mal utilisé ça peut faire perdre beaucoup plus de temps que ça en fait gagner. On peut gagner du temps car jusqu'ici, lorsqu'on voulait savoir comment une partie du framework était faite, on devait dégainer Reflector et regarder. C'est vrai qu'en ayant les sources sous la main et en permettant de faire du pas-à-pas dedans, ça fera gagner du temps. Bon, pour ma part j'utilise toujours Reflector, mais admettons ^_^ Ce qui me fait peur, en revanche, c'est le développeur mal informé mais plein de certitudes. Vous en avez forcément au moins un dans votre entourage, vous savez, le genre de personne qui est toujours prompte à imputer les problèmes de ses programmes à "la gestion mémoire foireuse de .NET" ou à "ce satané framework qui fait n'importe quoi" (alors qu'il n'a, bien sûr, jamais cherché à se renseigner sur le sujet, mais ça ne l'empêche pas d'en parler). Lui va perdre beaucoup de temps avec ça, car il va pouvoir faire du pas-à-pas dans les sources du framework, perdre une demie-journée à valider que non, la méthode String.Replace n'a pas de problème, et finalement découvrir que le problème venait de son propre code.
Attention cependant à ne pas tomber dans l'excès inverse. Une fois que vous êtes absolument certains que votre code est irréprochable, il n'y a rien de mal à remettre en question les bases sur lesquelles vous avez construit votre programme. L'OS, le framework et les bibliothèques que vous utilisez sont développées par des humains comme vous à qui il arrive de se tromper, ils ne sont donc pas exempts de bugs. Mais c'est vraiment, vraiment, vraiment rare. En ce qui concerne le code de l'OS et du framework, ils sont utilisés quotidiennement par des milliers et des milliers de personnes, la probabilité que soyez le découvreur d'un bug est donc très proche de zéro. En ce qui concerne les bibliothèques, la probabilité est déjà plus élevée, mais toujours assez faible (c'est aussi très dépendant de la maturité de la bibliothèque, vous aurez naturellement plus de chances de trouver des bugs dans une version 2 que dans une version 10). Pour vous donner une idée, sur les quatre dernières années, j'ai trouvé un bug dans un composant de reporting de DevExpress, et c'est tout.
Alors s'il vous plait, n'oubliez pas, quand vous êtes confrontés à un problème qui semble insoluble : vérifiez bien votre code avant de rejeter la faute sur celui des autres.
Si vous aussi vous développez des sites web et qu'on vous impose des exigences déraisonnables du genre "le site doit se charger rapidement" ou "le site doit être identique sous Internet Explorer et Firefox", ce post est fait pour vous.
J'ai remarqué ces derniers mois que le développeur web moyen, malgré un travail pas toujours facile, est rarement bien outillé. Pourtant, chercher une balise dans une soupe HTML de 400ko, tester une modification de CSS, débugger du Javascript, bref, toutes ces tâches qui vous font souffler un grand coup avant de vous y mettre, deviennent triviales pour peu qu'on soit bien outillé.
Voici donc la liste des outils que j'utilise quotidiennement pour me faciliter la vie.
Ceux que vous *devez* avoir : Firebug : l'arme ultime du développeur web, sous forme d'extension pour Firefox. Vous chercher à voir le code html d'une cellule perdue au milieu d'un tableau dans un tableau dans un tableau dans un tableau ? Faites un clic droit sur cette cellule puis choisissez "Inspect element", et Firebug vous montrera tout. Vous voulez tester un changement de CSS ? Pas de problème, Firebug permet d'éditer les styles à la volée. Un développement Javascript à débugger ? Facile, vous pouvez mettre des points d'arrêt et faire du pas-à-pas dans le code. YSlow : cette extension Firefox, qui peut s'intégrer à Firebug, permet de faciliter la mise en pratique des bonnes pratiques professées par Steve Souders et son équipe. Rien à ajouter, si ce n'est que si vous ne connaissez pas ces règles, allez les lire, ça vaut franchement le coup. Web Developer Toolbar : encore une extension Firefox, plus orientée graphisme, puisqu'elle permet par exemple de redimensionner la fenêtre de votre navigateur de façon à simuler une certaine résolution d'écran, de désactiver le Javascript et/ou les CSS, de valider votre code auprès du W3C, d'afficher les bordures des tableaux/cellules, etc. Je pense n'utiliser que 10% des possibilités de cette extension, mais ces 10% suffisent largement à la faire figurer dans cette liste. IETab : cette extension permet de tester vos créations sous Internet Explorer sans quitter Firefox. Le changement de moteur de rendu se fait en cliquant tout bêtement sur une icone, on ne fait pas plus simple. IE Developer Toolbar : un semblant de Web Developer Toolbar dédiée à Internet Explorer. Rien d'aussi impressionnant que sa consoeure sous Firefox, mais c'est déjà un bel effort qui fait gagner beaucoup de temps.
Ceux dont on n'a pas besoin tous les jours mais qu'on est bien contents de trouver : Ruler : une règle, qui vous permet facilement de mesurer des choses à l'écran (en pixels). Fiddler : Cet outil permet de suivre toutes les échanges HTTP entre votre navigateur et l'internesque qui clique. Très pratique pour par exemple vérifier que la compression, le cache et les dates d'expirations fonctionnent bien. L'outil fonctionne tout seul avec Internet Explorer, mais avec Firefox il faudra modifier la configuration du proxy pour que ça fonctionne (mettre le proxy à localhost sur le port 8888). SwitchProxy Tool : une extension Firefox qui permet de changer de réglages du proxy en un clic (je vous laisse deviner à quoi il est particulièrement utile) (indice : ça a un rapport avec Fiddler :-]). TcpView : un des nombreux utilitaires des extraordinaires Mark Russinovich et Bryce Cogswell, qui permet de voir les connexions réseaux ouvertes sur une machine. C'est donc une espèce de netstat graphique, parce que de temps en temps c'est bien de pouvoir vérifier que "attends, je serai pas connecté au mauvais serveur de base de données, là ?".
Voilà, avec tout ça vous n'avez plus d'excuses, il faut faire des sites qui déchirent, maintenant :-)
Symptome : vous disposez d'un hébergement MSDN chez Ikoula, et vous y avez installé un site en Asp.net qui utilise l'authentification Forms. Après vous être identifiés sur le site (quand ça fonctionne), votre session se termine brutalement après un temps aléatoire (mais compris dans les 5 minutes).
Vos logs vous indiquent :
Des erreurs de validation de viewstate (Validation of viewstate MAC failed...)
Des CryptographicException (Padding is invalid and cannot be removed...), en général sur WebResource.axd
Solution : renseigner vous-même dans le web.config les clés utilisées pour encrypter/décrypter les données qui transitent entre le client et le serveur. Voici une page qui génère le tag qui va bien (cette page provient d'un article sur la machine key), prêt à être copié/collé dans la balise <system.web> de votre fichier de configuration.
Par contre je ne comprends pas très bien pourquoi ça ne fonctionnait pas. Est-ce que le serveur décidait brusquement de changer de clé de cryptage entre deux aller-retour serveur ? Ca expliquerait pourquoi le viewstate était rejeté et les CryptographicException, mais ça me parait quand même bizarre...
Voici une vidéo où il montre comment transformer ses doigts en Wiimote (ou presque) :
Vous vous souvenez de Surface ? Mais si, rappelez-vous, l'espèce de table magique de Microsoft. Une des fonctionnalités de la bête qui avait été mise en avant était le multi-touch, où le fait d'avoir un écran tactile sur lequel on peut interagir à plusieurs endroits en même temps (si vous ne vous souvenez pas, pensez iPhone, il en fait autant). D'après ce que j'ai pu lire un peu partout, ce genre de chose coûte cher. Johnny, lui, fait ça avec quelques dollars de matériel et une Wiimote :
Pour terminer, une démo de head tracking, autrement dit le fait de savoir où se trouve la tête du joueur et d'adapter l'image en conséquence de façon à présenter une image en "vraie" 3D (regardez la vidéo, c'est limpide une fois qu'on l'a vue ^_^), toujours avec l'aide d'une Wiimote :
Comme vous pouvez le voir Johnny est quelqu'un de très actif :-)
Si vous voulez suivre ses projets, il a créé un blog à cet effet.
Les exceptions, c'est comme le fugu : si c'est bien cuisiné, c'est classe, sinon, on meurt.
Ayant récemment changé de mission, j'ai eu l'occasion de lire pas mal de code dernièrement, et disons que, pour garder la métaphore culinaire, c'est plus souvent du Tricatel que du Bocuse.
Ca n'est pas si atroce que ça (mais si j'en rajoute pas c'est pas drôle), cela dit j'ai trouvé quelques perles, et c'est l'une d'entre elles qui m'a amener à écrire ce post. Le morceau de choix qui m'a poussé à poster ici consistait à utiliser des blocs try..catch comme une structure de contrôle, autrement dit là où une paire de if aurait fait l'affaire.
Voici un petit exemple pour illustrer : on souhaite afficher le titre d'un livre (n'importe lequel) en français, et s'il n'y en a pas, en afficher un en anglais. S'il n'y en a pas non plus, on devra afficher un message d'erreur. Pour ce faire, nous avons à notre disposition une méthode GetBookTitles, qui nous renvoie tous les titres de livres dont on dispose dans la langue demandée. Ces titres sont renvoyés sous forme de tableau de chaines de caractères, et si aucun titre n'est disponible dans la langue demandée, ce tableau sera vide. On devra donc prendre garde à vérifier que le tableau n'est pas vide avant d'aller lire dedans... ou pas :
try
{string title = GetBookTitles("fr")[0];
DisplayTitle(title);
}
catch
{
try
{string title = GetBookTitles("en")[0];
DisplayTitle(title);
}
catch
{string title = "Impossible de charger le titre.";
DisplayTitle(title);
}}
Dans le premier bloc try, on récupère les titres de livres en français et on essaye tout de suite de lire le premier, sans vérifier qu'il existe. Si ça fonctionne, on affiche ce titre, sinon l'exécution passe au bloc catch. Ici, on applique la même technique pour récupérer les titres en anglais. Si ça ne fonctionne pas, on passe au bloc catch suivant, où on affiche le message d'erreur.
Voyons à présent le même code, écrit cette fois avec des if :
string[] titles = GetBookTitles("fr");
if(titles.Length > 0){string title = titles[0];
DisplayTitle(title);
}else{
titles = GetBookTitles("en");
if(titles.Length > 0){string title = titles[0];
DisplayTitle(title);
}else{string title = "Impossible de charger le texte.";
DisplayTitle(title);
}}
On récupére les titres des livres en français. S'il y en a, on affiche le premier, sinon on récupère les titres des livres en anglais. S'il y en a, on affiche le premier, sinon on affiche un message d'erreur.
Quel code vous semble le plus facile à relire ? :-)
En vrai, on écrirait d'ailleurs plutôt ça :
string title = "Impossible de charger le texte.";
string[] titles = GetBookTitles("fr");
if(titles.Length == 0){
titles = GetBookTitles("en");
}if(titles.Length > 0){
title = titles[0];
}
DisplayTitle(title);
Et là, quel code vous semble le plus facile à relire ?
Au-delà des problèmes de lecture, et donc de maintenabilité, que pose l'emploi de cette technique vient s'ajouter le problème des performances. En effet, si le coût d'un bloc try..catch est nul tant qu'il n'y a pas d'erreurs, l'addition devient salée en cas de problèmes. Voici des captures d'écran d'une petite application de test que j'ai écrit. Je pense que les chiffres parlent d'eux-mêmes (si ça vous intéresse, vous pouvez télécharger le code source de l'application de test).
Si tout se passe bien, les deux méthodes sont quasi-équivalentes.
Si on ne dipose pas de la version française des titres de livres, le code est plus de 400 fois plus rapide lorsqu'on utilise des if.
Si on ne dispose des titres les livres dans aucune langue, bizarrement le if est encore plus rapide qu'avant (peut-être parce dans ce cas on n'a pas de lecture à faire dans un tableau ?), ce qui le rend 1200 fois plus rapide.
Je répète : dans le pire des cas, le code qui utilise des exceptions est 1200 fois plus lent que son homologue utilisant des if.
Voilà, conclusion : utiliser les exceptions comme structure de contrôle, c'est tordu et lent. J'espère que ça aura convaincu ceux d'entre vous qui écrivent ce genre de choses que ce n'est pas une bonne idée.
Mais vraiment pas.
23:19 » Désinstaller Visual Studio 2008 beta 2 - programmation
Comme je sais que avez tous un abonnement MSDN sur mininova, vous avez dû vous jeter sur la version finale de Visual Studio 2008, disponible depuis quelques jours. Si vous aviez précédemment installé la version beta 2, lisez le post de Scott Guthrie à propos de sa désinstallation, car on a vite fait de flinguer une installation de Windows en faisant n'importe quoi (la beta 1 m'a servi de leçon ^_^).
Si vous ne lisez pas l'anglisse ou que ça vous gonfle, en voici la substantifique moëlle : "y'a plein de trucs à désinstaller, et ce dans un certain ordre". Voilà.
J'ai donc suivi la liste du post que j'ai mentionné, et vous retrouverez ici la liste de ce que j'ai désinstallé : les noms diffèrent parfois de la liste orginale, et j'ai même supprimé certaines choses qui n'y figuraient pas, mais bon, mon OS est encore vivant donc je vous transmets la recette :)
MSDN Library for Visual Studio 2008 Beta 2 - ENU (n'oubliez pas d'exporter votre configuration dans un fichier avant de désinstaller si vous voulez pouvoir la restaurer plus tard) (ça se passe dans Tools -> Import and Export Settings ^_^)
Microsoft SQL Server Compact Edition 3.5*
Microsoft SQL Server Compact Edition 3.5 Design Tools*
Microsoft SQL Server Compact Edition 3.5 Design Tools*
Microsoft Visual Studio Codename Orcas Performance Collection Tools - ENU
Windows Mobile 5.0 SDK R2 for Pocket PC
Windows Mobile 5.0 SDK R2 for Smartphone
Crystal Reports 2007*
Visual Studio Asset System*
Microsoft Visual Studio Web Authoring Component
Visual Studio 2005 Tools pour Office Second Edition Runtime (m'a proposé de redémarrer ma machine, mais j'ai refusé)
Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office System Runtime Language Pack *
Microsoft Visual Studio Tools for Office Runtime 3.0
Microsoft Document Explorer 2008 (le programme de désinstallation est titré "Microsoft Document Explorer 2007 Setup" ^_^)
Microsoft Document Explorer 2005
Microsoft Device Emulator version 3.0 - ENU
Microsoft .NET Compact Framework 3.5 Pre-Release
Microsoft .NET Compact Framework 2.0 SP2
.NET Framework 2.0 SDK*
Microsoft Visual Studio Codename Orcas Remote Debugger*
Microsoft Visual Studio 64bit Prerequisites Beta*
Microsoft .NET Framework 3.5 (Pre-Release Version) La liste originale s'arrête ici
Microsoft Silverlight Tools Alpha for Visual Studio 2008 Beta 2
Microsoft Visual Studio Team System 2008 Team Suite - ENU (of course :) )
* : indique que je n'ai rien trouvé à supprimer qui correspondait à ce nom sur ma machine
Ceci fait, vous pouvez redémarrer votre machine, puis installer Visual Studio 2008 et la MSDN qui va avec.
Une dernière note, Scott Guthrie conseille de remettre à zéro la configuration de Visual Studio avant de l'utiliser. Au premier lancement, allez donc dans le menu Tools -> Import and Export Settings puis choisissez l'option "Reset Settings" (et n'oubliez pas que vous pouvez importer/exporter votre configuration de Visual Studio 2005 et 2008 beta 2, si vous la perdez c'est vraiment que vous l'avez fait exprès).
Voilà, allez faire des programmes de ouf, maintenant.
Si vous aussi, après plusieurs années d'abstinence, vous replongez vos p'tites mains délicates dans la boue verdâtre et bouillonnante du C++, je vous promets de nombreuses séances d'arrachages de cheveux. Pour vous en éviter une et ainsi contribuer à leur préservation, voici un tutorial trodlabal intitulé :
Déclarer une variable membre privée statique en C++<
// Dans la classe, ça se passe comme on s'y attendrait// (modulo le fait qu'on ne peut pas initialiser les variables si elles ne sont pas const)class MaSuperClasse
{public:
staticint m_publique;
private:
staticint m_privee;
};
// En revanche, ensuite ça devient surnaturel :// Il faut *redéclarer* les variables// (cette correction vous est offerte par snihf)// avec du code en vrac, comme ça.int MaSuperClasse::m_publique = 0;
int MaSuperClasse::m_privee = 0;
}
Voilà, moralité : C# et Java sont quand même bien confortables :)
Petite explication de cette bizarrerie par l'ami snihf :
Une variable membre d'instance d'une classe est déclaré dans la déclaration de la classe, et défini lors de l'instanciation de la classe. Pour un membre statique, il n'y a pas d'instanciation, il est donc nécessaire de le définir à part, dans un fichier de définitions.
19:43 » Fmod ex, WIN32, et l'édition de liens - programmation
Note pour plus tard : sous Windows, ne pas oublier de définir WIN32 avant d'essayer de linker son projet à la librairie fmodex_vc.lib, sous peine de se manger une brouettée d'erreurs d'édition de liens en la personne de notre LNK2019 préférée.
Je recopie une des erreurs pour nos amis les moteurs de recherche :
unresolved external symbol _FMOD_System_Create referenced in function "enum FMOD_RESULT __cdecl FMOD::System_Create(class FMOD::System * *)" (?System_Create@FMOD@@YA?AW4FMOD_RESULT@@PAPAVSystem@1@@Z) main.obj
Comment obtenir une référence Javascript sur un élément graphique ?
Il faut utiliser la méthode findName. Elle prend en paramètre le nom de l'élément qu'on souhaite récupérer : ce nom correspond à ce qui a été défini dans les attributs x:Name du code xaml. On peut appeler cette méthode depuis la propriété content de l'objet représentant le contrôle Silverlight, mais elle est disponible sur n'importe quel contrôle, et l'élément dont le nom est passé en paramètre est recherché dans l'intégralité de l'arbre des contrôles et pas uniquement dans les descendants de l'élément à partir duquel l'appel est réalisé, on peut donc y aller comme des foufous et l'appeler de n'importe où :)
Comment changer la valeur des propriétés des éléments graphiques ?
Dans la plupart des cas, on le fait de manière classique :
monElementGraphique.Propriete = valeur;
Les attached properties doivent cependant être traitées différemment. Par exemple, pour changer la valeur de la propriété Canvas.Top, on écrira :
monElementGraphique.["Canvas.Top"] = valeur;
Comment télécharger du contenu ?
Grâce à l'objet downloader. On en crée une instance en appelant la méthode createObject de l'objet correspondant au contrôle Silverlight. L'objet que nous obtenons permet de télécharger un contenu depuis une url. Le contenu doit être dans le même domaine que l'application Silverlight : l'objet downloader est basé sur l'objet XMLHttpRequest et hérite donc de l'impossiblité de faire des requêtes cross-domain.
var objetDownloader = controleSilverLight.createObject("downloader");
Avant de faire récupérer des choses à l'objet, nous devons ajouter un handler pour son évènement completed, qui annonce la fin du téléchargement. En effet, le downloader effectue ses tranferts de manière asynchrone, nous devons donc forcément gérer l'évènement completed si on souhaite récupérer les données téléchargées.
var tokenDownloader = objetDownloader.addEventListener("completed", Silverlight.createDelegate(this, this.HandleDownloadCompleted));
On indique ensuite à l'objet quoi télécharger, par le biais de la méthode open, qui prend en premier paramètre la méthode http à utiliser (ex : "GET"), et en second l'adresse de la ressource à récupérer.
Enfin, on lance le transfert grâce en appelant la méthode send.
objetDownloader.send();
Le téléchargement étant à présent lancé, voyons comment récupérer les données dans le gestionnaire de l'évènement completed. Ce dernier accepte deux paramètres : sender, qui est une référence sur l'objet qui a signalé cet évènement (i.e notre objet downloader), et eventArgs, qui représente les paramètres associés à l'évènement. Pour récupérer les données, nous pouvons appeler la méthode getResponseText() de l'objet downloader. Cette méthode prend un argument qui permet d'indiquer, dans le cas où on a téléchargé un fichier zip, quel fichier de l'archive on souhaite récupérer. S'il ne s'agit pas d'un fichier zip, il suffit de passer une chaine de caractères vide en paramètre, ou d'utiliser directement la propriété ResponseText.
HandleDownloadCompleted: function(sender, eventArgs){// ces deux lignes ont le même effetvar data = sender.getResponseText("");
data = sender.ResponseText;
// pour ne pas dégrader les performances
sender.removeEventListener("completed", tokenDownloader);
sender = null;
}
Comme vous pouvez le voir dans le code ci-dessus, une fois les données récupérées je supprime le handler de l'évènement completed puis je mets la référence au downloader à null, ce qui d'après une page de la MSDN permet d'améliorer les performances des applications Silverlight.
Notez que la méthode removeEventListener() réclame un token en paramètre : ce token est renvoyé par la méthode addEventListener.
J'ai écrit le code d'un joli bouton en xaml. Comment l'afficher ?
Je pars du principe que le code xaml dont on parle ne fait pas partie du fichier xaml qu'on indique comme source au contrôle Silverlight (sinon il serait déjà affiché :) ).
Premièrement, si ce n'est pas déjà fait, il faut télécharger le contenu du fichier xaml (voir Comment télécharger du contenu ?).
Ensuite, une fois qu'on a récupéré la chaine de caractères correspondant au contenu du fichier xaml, il faut transformer cette chaine en objets Javascript.
Cela se fait à l'aide de la méthode CreateFromXaml() de la propriété content de l'objet représentant le contrôle Silverlight. Il prend en premier paramètre le code xaml à partir duquel créer les contrôles, et en second un booléen optionnel (false par défaut) qui indique, s'il est à true, que la méthode doit modifier les éventuels noms des contrôles (i.e le contenu de l'attribut x:Name) afin d'éviter les collisions.
// on suppose que la variable "xaml" contient le code xaml à affichervar controle = controlSilverLight.content.CreateFromXaml(xaml, true);
Nous obtenons donc notre/nos contrôle(s), que nous devons à présent ajouter à l'arbre des contrôles pour qu'ils soient affichés. Pour cela, il suffit d'avoir une référence à un élément de type Canvas, qui fait office de contrôle conteneur en Silverlight. Sa propriété children correspond à l'ensemble des contrôles qu'il contient, et nous y ajoutons les contrôles que nous venons d'obtenir grâce à sa méthode add.
// on suppose que la variable "root" contient une référence vers un objet Canvas
root.children.add(controle);
Comment cacher un élément ?
Mettez sa propriété Visibility à... Collapsed :) (hé non, pas Hidden)
Les deux valeurs possibles de cette propriété sont Visible et Collapsed.
this.MainCanvas.Visibility = "Collapsed";
Comment être notifié lorsque l'image affichée par un contrôle Image a terminé son chargement ?
Si ça n'a pas grand intérêt pour les images en local (le temps de chargement est proche de zéro), ça devient intéressant lorsqu'on va chercher les images à la demande.
Pour cela, il suffit d'ajouter un handler à l'évènement DownloadProgressChanged. Dans le handler, vous pouvez consulter la valeur de sender.DownloadProgress pour savoir où en est le téléchargement. La valeur varie entre 0 et 1 (1 indique que le téléchargement est terminé).
this.Image.addEventListener("DownloadProgressChanged", Silverlight.createDelegate(this, this.ImageLoading));
this.Image["Source"] = "http://www.mondomaine.com/monImage.png";
// handler de l'évènement DownloadProgressChanged
ImageLoading: function(sender, eventArgs){if(sender.DownloadProgress == 1)// on vérifie que le téléchargement est terminé{// ...}}
Comment contrôler une animation depuis le code Javascript ?
Supposons que votre xaml contienne un Storyboard portant le doux nom de "pouet". Il faudra d'abord obtenir une référence dessus (grâce à findName), et vous pourrez ensuite utiliser les méthodes Begin, Pause, Resume, Seek et Stop pour contrôler l'animation.
// Obtenir une référence sur l'animation "pouet"var animation = this.target.findName("pouet");
// Démarrer l'animation "pouet"
animation.begin();
Comment être notifié lorsqu'une animation est terminée ?
Il suffit de gérer l'évènement Completed de l'animation :
// Obtenir une référence sur l'animation "pouet"var animation = this.target.findName("pouet");
// Démarrer l'animation "pouet"
animation.addEventListener("Completed", Silverlight.createDelegate(this, this.HandleAnimationCompleted));
Comment récupérer la taille totale de l'application Silverlight en pixels ?
La taille en pixels de l'application est contenu dans les propriétés actualWidth et actualHeight de la propriété content de l'objet Silverlight :
var largeur = controleSilverLight.content.actualWidth;
var hauteur = controleSilverLight.content.actualHeight;
Comme la techno m'intriguait, j'ai passé un petit week-end au début du mois à m'amuser avec Silverlight, le pseudo-Flash de Microsoft. J'ai donc réalisé une petite interface pour ma collection de CDs, qui pour une raison que j'ignore ne fonctionne pas sous Firefox. Je vous conseille donc fortement de la consulter avec Internet Explorer, ou, si vous ne pouvez pas vous passer du Renard Qui A Le Feu Au Cul, avec IE Tab, la géniale extension qui permet de consulter des pages via IE sans quitter Firefox.
Comme d'hab, la première page vous présente la liste de CDs sous forme d'images de leurs pochettes respectives :
Lorsqu'on clique sur une de ces pochettes, un cadre contenant des informations complémentaires s'affiche. Ces infos sont récupérées grâce aux web services d'amazon.
Je vous préviens tout de suite, ce n'est absolument pas terminé : il n'y a entre autres pas de scrollbars si le contenu de la page dépasse la taille de son contenant, il est préférable d'attendre que toutes les images soient chargées avant de cliquer partout, et je vous conseille d'attendre quelques secondes s'il ne se passe rien après que vous ayez cliqué sur la pochette d'un CD.
Hop, un petit lien pour télécharger les sources si vous avez envie de vous plonger là-dedans.
Il s'agit de Silverlight 1.0, autrement dit tout le code est en Javascript (la version 1.1 de Silverlight permet d'utiliser les langages du framework .NET).
Vous y trouverez les fichiers suivants :
Default.html : c'est sur cette page que vous vous rendez pour voir l'application. Elle contient les références aux fichiers Javascript ainsi qu'un appel à la fonction createSilverlight(), qui crée le contrôle Silverlight sur la page.
Silverlight.js : ce fichier, fourni avec le sdk de Silverlight, définit quelques méthodes nécessaires au bon fonctionnement de l'application (notamment CreateObject, mais on y reviendra).
Default.html.js : contient la fonction createSilverlight, qui est appelée par Default.html pour créer le contrôle Silverlight. Elle contient également la méthode Silverlight.createDelegate (on y reviendra également). Je ne sais plus trop comment j'ai obtenu ce fichier, il me semble que Visual Studio me l'a généré. Au pire, la fonction createSilverlight est disponible dans le fichier CreateSilverlight.js du sdk.
Scene.xaml : ce fichier définit l'interface graphique générale.
Scene.xaml.js : contient le code qui peuple la page avec les images des CDs.
ImageButton.xaml : contient la définition graphique du contrôle chargé d'afficher l'image d'un pochette.
ImageButton.js : contient le code lié au contrôle précédent, qui décrit notamment la réaction à certains évènements.
CDInfo.xaml : contient la définition graphique du cadre qui est affiché lorsqu'on clique sur une pochette de CD.
CDInfo.js : contient le code qui peuple le cadre et qui gère la réaction à certains évènements.
Pour vous expliquer un peu le code, nous allons suivre le déroulement du programme.
Au début il n'y avait rien. Puis un navigateur web se rendit à la page Default.html. Cette page, comme je l'ai écrit plus haut, appelle la fonction createSilverlight() pour créer le contrôle Silverlight. Vous pouvez éditer cette fonction afin de customiser le contrôle qui va être créé :
La fonction commence par instancier la classe Peuw.Scene (définie dans le fichier Scene.xaml.js), qui correspond à la "fenêtre" principale de l'application. La fonction createObjectEx est ensuite appelée, pour créer le contrôle Silverlight, et c'est son appel que nous pouvons modifier. Le paramètre source indique quel fichier xaml doit être chargé au démarrage (si le terme "xaml" ne vous dit rien, sachez qu'il s'agit du langage utilisé pour décrire la partie graphique des applications Silverlight (et WPF) ). Le paramètre properties vous permet de customiser l'apparence du contrôle. Ici, nous avons demandé un contrôle qui occupe la totalité de l'espace disponible et dont la couleur d'arrière-plan est le noir (les couleurs sont indiquées comme en html, avec un premier octet supplémentaire pour la transparence). Le paramètre events permet de définir quelles méthodes répondront à quels évènements (il s'agit bien sûr uniquement des évènements liés au contrôle Silverlight, on ne doit pas tous les définir ici). Ici, nous demandons à ce que l'évènement onLoad soit géré par la méthode scene.handleLoad (ce qui explique pourquoi la classe Peuw.Scene a été instanciée), qui servira donc de point d'entrée au programme.
Notez l'utilisation de la méthode Silverlight.createDelegate, qui facilite le branchement d'une méthode d'instance sur un évènement (elle retourne une fonction correspondant à l'appel objet.methode, objet et methode étant passés en paramètre).
Ceci fait, notre contrôle Silverlight est créé. Que se passe-t-il ensuite ? L'évènement Load du contrôle Silverlight est déclenché, ce qui a pour effet d'exécuter la méthode que nous avons indiqué dans createSilverlight().
Cette méthode a pour but, en plus de faire un peu d'initialisation, de lancer la récupération de la liste des CDs au format JSON (JavaScript Object Notation, qui permet de représenter des objets Javascript en simple texte).
Elle commence donc par mettre de côté une référence au contrôle Silverlight, qui nous est donnée dans le paramètre plugIn. On récupère ensuite des références vers le cadre principal de l'application et celui qui va contenir les images des pochettes de CD. Pour mieux comprendre ces deux lignes, regardons le code xaml qui est chargé :
La balise Canvas représente un canevas sur lequel nous allons pouvoir disposer des contrôles graphiques. Nous en avons défini un à la racine du document avec le nom "Main", qui est défini par l'attribut x:Name. Nous lui avons également donné une taille, mais ce n'est pas tellement important puisque, même si nous ajoutons des contrôles à des coordonnées qui "dépassent" du canevas, ils seront affichés magré tout. Dans ce canevas, nous avons créé un second canevas portant le nom "CDs", qui contiendra les images des pochettes de CD.
Revenons à présent au code Javascript : pour récupérer une référence vers un élément graphique, nous utilisons la méthode findName. Elle prend en paramètre le nom de l'élément qu'on souhaite récupérer : ce nom correspond à ce qui a été défini dans les attributs x:Name du code xaml. Nous appelons cette méthode depuis la propriété content de l'objet représentant le contrôle Silverlight, mais elle est disponible sur n'importe quel contrôle, et l'élément dont le nom est passé en paramètre est recherché dans l'intégralité de l'arbre des contrôles et pas uniquement dans les descendants de l'élément à partir duquel l'appel est réalisé, on peut donc y aller comme des foufous :)
Nous en arrivons à présent à la classe downloader, dit "L'Indispensable". On en crée une instance en appelant la méthode createObject de l'objet correspondant au contrôle Silverlight, qui à ma connaissance n'a pour l'instant pas d'autre utilité. L'objet que nous obtenons permet de télécharger un contenu depuis une url. Le contenu doit être dans le même domaine que l'application Silverlight : l'objet downloader est basé sur l'objet XMLHttpRequest et hérite donc de l'impossiblité de faire des requêtes cross-domain. Nous utilisons cet objet pour récupérer la sortie d'un script php qui nous renvoie la liste des CDs ainsi que quelques infos, le tout au format JSON.
Si vous souhaitez tester l'application en local et que ne voulez pas vous embêter avec votre serveur web, j'ai inclus deux fichiers texte dans l'archive contenant les sources. Ces deux fichiers contiennent le JSON correspondant à la liste de CDs (cds.txt) et celui des détails d'un CD (review-tracks.txt).
Revenons à nos moutons : notre downloader est créé, mais avant de lui faire récupérer des choses, nous ajoutons un handler pour l'évènement completed, qui survient lorsque le téléchargement est terminé. En effet, le downloader effectue ses tranferts de manière asynchrone, nous devons donc forcément gérer l'évènement completed si on souhaite récupérer les données téléchargées.
On indique ensuite à l'objet quoi télécharger, par le biais de la méthode open, qui prend en premier paramètre la méthode http à utiliser (pour nous, "GET"), et en second l'adresse de la ressource à récupérer. Ici, nous avons inscrit l'adresse du script php qui nous renvoie les données au format JSON.
Enfin, on lance le transfert grâce en appelant la méthode send.
Voyons à présent ce qui se passe lorsque le téléchargement est terminé :
Le gestionnaire de l'évènement accepte deux paramètres : sender, qui est une référence sur l'objet qui a signalé cet évènement, et eventArgs, qui représente les paramètres associés à l'évènement (si vous faites du .NET, ça doit vous sembler étrangement familier :) ). Ici, sender représente donc l'objet downloader que nous avons créé dans la méthode handleLoad. Nous appelons sa méthode getResponseText() pour obtenir les données transférées. L'argument passé à la méthode permet d'indiquer, dans le cas où on a téléchargé un fichier zip, quel fichier de l'archive on souhaite récupérer. Ici, nous récupérons directement une chaine de caractères, donc nous passons une chaine vide en paramètre (on aurait pu utiliser la propriété ResponseText, qui aurait eu le même effet).
Cette chaine de caractères est immédiatement evaluée afin de transformer le JSON en objets Javascript.
Au passage, j'aurais bien utilisé le parser JSON de json.org, mais il n'avait pas l'air de s'entendre avec le contenu de Silverlight.js. Le risque de sécurité étant mineur (je suis le producteur des données qui sont consommées par l'application, donc bon), je n'ai pas insisté ^_^
Ceci fait, je supprime le handler de l'évènement completed puis je mets la référence au downloader à null, ce qui d'après une page de la MSDN permet d'améliorer les performances des applications Silverlight.
Notez que la méthode removeEventListener() réclame un token en paramètre : ce token est renvoyé par la méthode addEventListener (on l'a récupéré dans la méthode handleLoad).
Nous avons donc notre liste de CDs. Maintenant, nous créons à nouveau un objet downloader afin d'aller récupérer un fichier xaml à partir duquel nous créerons le contrôle destiné à l'affichage des informations de détail sur un CD particulier.
J'aurais pu effectuer cette tâche dans la méthode handleLoad, mais j'ai préféré le faire ici afin d'être sûr que le chargement se faisait dans un certain ordre, et surtout que le chargement de l'ensemble des données était réalisé avant de laisser les utilisateurs cliquer partout. Je me rends compte maintenant que j'aurais mieux fait d'utiliser un fichier zip... enfin bref.
Donc voilà, je ne détaille pas plus, on a déjà vu tout ça quand on a récupéré la liste de CDs.
Voyons voir ce qui se passe lorsque notre fichier xaml a été téléchargé :
Nous récupérons la chaine de caractères correspondant au contenu du fichier demandé grâce à la propriété ResponseText (pour changer un peu). Nous souhaitons transformer cette chaine en objets Javascript que nous pourrons ajouter à l'arbre de nos contrôles. Pour cela, nous utilisons la méthode CreateFromXaml() de la propriété content de l'objet représentant le contrôle Silverlight. Il prend en premier paramètre le code xaml à partir duquel créer les contrôles, et en second un booléen optionnel (false par défaut) qui indique, s'il est à true, que la méthode doit modifier les éventuels noms des contrôles (i.e le contenu de l'attribut x:Name) afin d'éviter les collisions.
Nous obtenons donc nos contrôles, que nous ajoutons à l'arbre des contrôles : this.root contient une référence vers le canevas général. Sa propriété children correspond à l'ensemble des contrôles qu'il contient, et nous y ajoutons les contrôles que nous venons d'obtenir grâce à la méthode add.
On instancie ensuite la classe Peuw.CDInfo, qui s'occupe de gérer les contrôles que nous venons de charger (redimensionnement, récupération des infos, gestionnaires d'évènement, etc). On garde une instance de cette classe en variable membre pour plus tard.
Nous attaquons ensuite la dernière étape du chargement : récupérer le code xaml qui définit le "bouton" qui va afficher les pochettes de CD et sur lequel les utilisateurs pourront cliquer afin de consulter les informations détaillées du CD.
Je ne détaille pas la méthode CreateImages, qui n'apporte rien de nouveau. Elle crée les contrôles à partir du code xaml autant de fois qu'il y a de CDs et les ajoute au canevas en les positionnant correctement.
Soulignons tout de même que, pour obtenir la taille de l'application, nous utilisons les propriétés actualWidth et actualHeight de la propriété content de l'objet Silverlight :
var largeur = this.plugIn.content.actualWidth;
var hauteur = this.plugIn.content.actualHeight;
Ces propriétés représentent la taille à l'écran, pas celle spécifiée. Dans notre cas, nous avions demandé à ce que le contrôle Silverlight prennent 100% de la hauteur et 100% de la largeur disponibles, ce qui est certes pratique, mais devient ennuyeux lorsqu'on souhaite adapter la disposition du contenu en fonction de la taille du contenant. Heureusement, ces propriétés nous renvoient des valeurs en pixels (qui seront donc différentes si par exemple on change la taille de la fenêtre du navigateur).
A ce stade, l'application est chargée. Graphiquement, nous sommes arrivés à la première capture d'écran.
C'est ici que se terminent les explications pour ce post : nous avons créé des contrôles, branché des gestionnaires d'évènement et chargé des données, donc je pense que vous avez le nécessaire pour comprendre comment fonctionne le reste.
Je vais reprendre les notions vues ici sous une forme plus digeste dans un autre post, auxquelles j'ajouterai les quelques petites choses que j'ai découvert en écrivant cette application.
En attendant, bilan de l'opération : j'aime bien Silverlight, mais si j'en refais ça sera du 1.1, c'est trop fatigant le Javascript :)
Ah, et ça manque de contrôles : typiquement, les scrollbars. S'il n'y en a pas, c'est pas parce que j'aime pas les scrollbars (everybody loves scrollbars \0/), mais plutôt parce que si vous en voulez, vous devrez les coder vous-même, et bizarrement j'ai eu la flemme ^_^
D'après ce que j'ai vu, le SDK de la version 1.1 viendrait avec quelques contrôles en exemple, dont des scrollbars... à suivre.
Juste un petit mot pour vous dire que si comme moi vous êtes joueurs et que vous avez prévu d'installer la CTP de juillet d'Acropolis sur votre install' toute fraîche de la beta 2 d'Orcas, *ne le faites pas*.
Si vous le faites, au prochain lancement de Visual Studio, vous serez accueillis par quelques messages amicaux du genre "Package 'Visual Studio XML Editor Package' has failed to load properly" ou encore "Package 'Microsoft.Workflow.VSDesigner.DesignerPackage, Microsoft.Workflow.VSDesigner, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' has failed to load properly".
Voilà, maintenant vous savez, le monde ne peut plus fermer les yeux.
J'ai récemment remplacé un Winamp de plus en plus AOLisé par XmPlay, un lecteur qu'il est bien pour vos oreilles.
Il propose de base le support d'un grand nombre de formats, et si votre favori n'en fait pas partie (SPC par exemple), les plugins répondent à l'appel, d'autant que la bête accepte les plugins de Winamp (ceux dédiés à la lecture d'un format particulier, pas les autres).
Il dispose également d'une foule de fonctionnalités en standard, comme les raccourcis clavier system wide, le support CDDB, les inévitables skins, et moultes autres joyeusetés.
Il ne manquait plus qu'un plugin RisoliVillard, qui permet à n'importe quelle application de récupérer le nom de la chanson courante en se connectant au port 8462 de votre machine (c'est de cette façon que j'indique quelle chanson j'écoute lorsque je poste sur peuw) (ça et phpMyAdmin, parce que des fois je triche :-]), ce qui est maintenant chose faite \0/
Pour télécharger le plugin ainsi que son code source, cliquez ici.
Un post qui poste tout haut la question que nous autres pauvres hères forcés au Visual Basic nous posons parfois, lorsque la lune est rousse et que le spleen se fait si fort que nous sommes obligés, oui obligés de nous réfugier dans les paradis artificiels pour ne pas sombrer aussi bas que le voudrait notre réputation : pourquoi personne n'a de respect pour les programmeurs Visual Basic ?
Mise en situation : soit une application .NET 1.1 qui effectue des appels à des web services. La partie réseau se passe très bien, malgré la présence d'un proxy par lequel l'application doit passer afin de contacter les web services.
Un beau jour, l'adresse dudit proxy change, et patatras, l'application ne fonctionne plus.
Le plus inquiétant, c'est qu'Internet Explorer est bien configuré pour utiliser ce nouveau proxy, et .NET étant censé se baser sur ces paramètres afin de savoir quel proxy utiliser, ça devrait fonctionner... étrange.
Après quelques essais infructueux, je vais consulter, à l'aide de l'excellentissime Reflector, le code source de la méthode System.Net.WebProxy.GetDefaultProxy(), qui retourne un objet WebProxy correspondant aux paramètres d'Internet Explorer lus dans la base de registres.
Et là stupeur, la méthode ne va pas lire les valeurs sous la clé utilisée par Internet Explorer comme on s'y attendait (HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings), mais sous une clé un cran en dessous (HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections).
Et c'est là, dans la valeur binaire DefaultConnectionSettings, que se trouvent les paramètres lus par le framework .NET.
Effectivement, cette valeur pointait toujours vers l'ancien proxy, d'où le patatras. Une correction d'adresse de proxy plus tard, tout roulait, ouf ^_^
En espérant que ça vous évitera des prises de têtes :-) (et que ça vous poussera à utiliser Reflector, il est vraiment très très bien, cet outil).
18:31 » Un peu de technique : le viewstate, et throw vs. throw ex - programmation
Ce matin, en parcourant le dernier post du blog de Tess Ferrandez, je suis tombé sur le blog de Dave Reed.
En plus d'avoir le bon goût de coder sur fond noir (je me sens moins seul), il a écrit un post très très très intéressant sur le viewstate d'Asp.net. Si comme moi vous avez appris la technologie un peu à l'arrache et que vous vous sentez parfois limité lorsque les choses deviennent touchy, n'hésitez pas à lire son excellent post TRULY Understanding ViewState.
A propos des exceptions, je suis arrivé je ne sais plus trop comment sur ce post qui explique la différence entre utiliser throw ex et throw pour re-lever des exceptions qu'on a catché (où ex est l'exception catchée).
En gros c'est simple, dans le premier cas, l'exception qui remontera verra sa pile des appels tronquée au niveau de l'endroit où on la relance. On aura le reste de stack trace, mais rien de plus bas. Dans le second cas, la stack trace sera préservée.
Moi qui trouvait ça dommage qu'on soit obligé de perdre la pile lorsqu'on relance une exception, je sens que je vais modifier pas mal de code lundi ^_^