Welcome to MSDN Blogs Sign in | Join | Help
L’expérience utilisateur au cœur des projets

Les deux keynotes du MIX 09 ont fait la part belle à la notion d’expérience utilisateur. La présence de Bill Buxton durant les deux keynotes n’y est pas étrangère... Si aujourd’hui les  sites Web grand public sont visuellement travaillés, la notion d’expérience utilisateur est très rarement abordée dans de tels projets. Des technologies telles que Silverlight et WPF relancent la nécessité de penser à l’expérience utilisateur. Mais comment définir le terme d’expérience utilisateur ? Ce n’est pas une tâche facile car elle fait intervenir différentes composantes telle que l’ergonomie d’une application, son design, sa facilité d’utilisation, la simplicité des écrans, la compréhension du besoin de l’utilisateur, la réactivité de l’interface, etc. Ces deux keynotes furent l’occasion pour Bill Buxton et Deborah Adler de nous sensibiliser sur ce concept qui est un facteur clé de la réussite d’une application orientée utilisateur.

IMGA0004 Durant son premier keynote, Bill Buxton a commencé par introduire le concept de design en citant des designers ayant marqué l’industrie par leur création dans divers domaine tel que Andy Dreyfuss pour le téléphone filaire, Raymond Loewy pour la bouteille de coca-cola ou de Walter Dorwin Teague pour le premier appareil de photo Kodak. Le but de Bill Buxton était d’insister sur l’impact d’un design réussi et de l’empreinte que celui-ci peut laisser dans le temps. Effectivement, l’apparence des téléphones filaires ont peu changé avant l’apparition du “sans fil”. Image_2Il en est de même pour les appareils photos non numériques et que pensez de l’apparence de nos bouteilles d’aujourd’hui ? A part quelques essais novateurs comme la bouteille en forme de goute d’eau de Ora Ito, peu de révolution dans ce domaine.

Mais pourquoi l’apparence de ces objets n’ont guère changé depuis leur première apparition ? S’agit-il de leur design ? Il semblerait en écoutant Bill Buxton que le design n’est pas la première cause. Pour Bill Buxton ce qui compte c’est l’expérience que va procurer un design et non le design lui-même. Pour illustrer cela, il prit pour exemple un simple vélo cross. Certains trouveront ce vélo “beau”, tandis que d’autres ne le trouveront pas à leur gout. Mais ce qui prime c’est qu’il fournisse bien le service que l’on attend de lui et que l’on prenne du plaisir à l’utiliser. Bref, l’expérience que l’on va vivre grâce à lui.

Par exemple, appliquer au domaine du téléphone portable il convient de penser à l’expérience que l’on aura avec le téléphone et non l’apparence de son interface qui du fait découlera de source une fois l’expérience trouvée.

Ce fut une belle image pour présenter la notion de “sketchflow” que l’on a introduit dans Expression Blend 3. Le sketching permet d’exprimer une expérience sans s’attacher à sa représentation. imageEn intégrant le sketching dans un outil comme Expression Blend 3,image on apporte un moyen simple de partager cette expérience avec tous les acteurs d’un projet informatique (ergonome, fonctionnelle, designer, développeur et client final). Et comme le temps est un facteur qui limite souvent la recherche d’expérience utilisateur, l’outillage apporté dans Blend 3 optimisera ce workflow pour une meilleure productivité et un gain de temps. Une volonté était aussi d’attacher le moins d’importance possible à l’aspect des écrans afin de bien dissocier le design de l’expérience. Ceci a poussé l’équipe Blend à proposer un style imitant le crayonnage pour le sketching. De cette manière la lecture d’un écran ne se heurte pas à des considérations cométiques.

IMGA0006 Dans le deuxième keynote, Deborah Adler a démontré différemment la notion d’expérience utilisateur avec un projet qu’elle a réalisé en 2006. Inspirée par sa grand mère qui s’était trompé de médicament, son projet consistait à repenser le packaging des boites pour limiter les erreurs induites par un mauvais étiquetage. Bien que très loin de nos projets informatique son témoignage démontra un point essentiel de l’expérience utilisateur. Avant même de s’intéresser au nouveau design du packaging, il faut d’abord s’intéresser aux personnes à qui on s’adresse. L’expérience que celle-ci vont vivre. Quelles sont leurs habitudes, leurs problèmes, leurs besoins, etc.

Appliquer à notre domaine avant même de s’intéresser au look de nos interfaces, intéressons nous d’abord à comprendre nos utilisateurs et à définir l’expérience que l’on apporte…

La capture d’écran en Silverlight 3

Silverlight 3 offre maintenant la possibilité de travailler avec des bitmaps en mémoire. Cette fonctionnalité offre de nombreux avantages pour constituer en arrière plan une image de manière programmatique. Il est alors possible de changer très rapidement des images à la volée pour obtenir des effets visuels particuliers, transformer un visuel ou encore de texturer une surface 3D.

Mais une autre utilisation est de pouvoir capturer l’écran d’une application Silverlight et pourquoi pas de la sauvegarder par la suite sur le disque ou de l’envoyer via une connexion Web. Pour ce faire, il convient dans un premier temps de créer une image modifiable en instanciant la classe WriteableBitmap de l’espace de nom System.Windows.Media.Imaging avec la taille de l’image souhaitée.

WriteableBitmap wb = new WriteableBitmap(800, 600, PixelFormats.Pbgra32);

La classe WriteableBitmap permet alors d’accéder à chaque pixel de l’image au travers d’un tableau d’entiers. Mais elle dispose aussi d’une méthode Render qui prends deux paramètres : un élément visuel et une transformation à appliquer.

Grâce à cette méthode, il est alors possible de capturer le visuel d’un élément quelconque de Silverlight. Par contre, du à un bug de la béta actuelle (enfin je pense), il est obligatoire de fournir une transformation même si on ne désire pas en appliquer une.

Voici un exemple qui capture le conteneur le plus haut (donc le rendu complet de l’écran) et qui affiche le contenu avec une rotation de 20° dans un composant image du même écran.

WriteableBitmap wb = new WriteableBitmap(800, 600, PixelFormats.Pbgra32); wb.Render(LayoutRoot, new RotateTransform() { Angle = 20 }); image1.Stretch = Stretch.Uniform; image1.Source = wb;

Pour ne pas avoir de transformation, il suffit de mettre l’angle de rotation à 0. Ce bug sera certainement corrigé dans la version définitive car le prototype de la méthode accepte normalement la valeur null.

MIX Las Vegas 2009

Le MIX 2009 commence dans 30 min. Le keynote de ce matin abordera principalement la béta Silverlight 3, Windows Azure, Blend 3 et quelques nouveautés dans la suite Expression. Avec un petit groupe de collègue, nous écrirons quelques billets afin de vous faire part de toutes les nouveautés annoncées.

WebORB : un générateur de pdf pour Silverlight

Bien que non spécifique à la plateforme Silverlight, il est quand même intéressant de jeter un œil sur cette solution initialement destinée à Flash. Cette solution permet avec une syntaxe XML de définir et de générer un fichier PDF. Vous pouvez tester directement les exemples de la version Silverlight ici : http://www.themidnightcoders.com/weborbexamples/examples/silverlight/pdfgeneration/index.aspx

Pour plus d’information voici le site de l’éditeur : http://www.themidnightcoders.com/products/pdf-generator/overview.html

Chargement dynamique d’assembly en Silverlight

Ce sujet est assez bien couvert dans les différents billets sur Silverlight, mais je l’aborde de nouveau avec une vue orientée aux contraintes de RIA d’entreprise.

En effet, Silverlight couvre un large périmètre allant de la bannière publicitaire en passant par du contenu multi-média piloté par des interfaces plus ou moins sophistiquées. Mais de part sa conception, c’est tout naturellement que cette technologie est de plus en plus adoptée dans un contexte d’entreprise que ce soit pour une utilisation interne ou grand public. Dans les deux cas, il s’agit d’applications de gestion disposant d’un certain volume de données, d’écrans et de règles métier.

Et c’est bien sur ce point que le bat blesse… Contrairement à une application navigationnelle Web où les pages (en fait les données+logique applicative + IHM) sont téléchargées au fur à mesure de la navigation, une application RIA précharge tous les écrans pour éviter les aller/retour liés à la navigation. Bien sur, il n’est pas interdit d’effectuer des aller/retour avec le serveur, mais ces opérations ne doivent pas détériorer l’expérience utilisateur. Mais disposer de tous les écrans et les données a un cout : l’augmentation du temps de chargement.

Une parade est de découper physiquement en plusieurs assembly son application et de mettre en place un mécanisme de téléchargement dynamique du code. Selon les besoins ou les contraintes, une assembly pourra contenir un composant, un écran, une succession d’écran, etc. Dans certain cas, elles peuvent même ne contenir que des données. Bien pensé, ce découpage rendra l’accès et l’utilisation de l’application plus fluide quelque soit sa complexité et sa taille en nombre d’écran.

La mise à disposition de l’assembly

Pour illustrer ce concept de téléchargement de code en fonction des besoins notre assembly contiendra un formulaire contenu dans un conteneur grid. Ce formulaire se trouve dans l’assembly nommé CustomerFormContainer.dll et la classe représentant le formulaire se nomme CustomerFormContainer.CustomerForm.

Physiquement l’assembly doit être visible à l’application Silverlight de base. Il convient donc de créer un projet Web pour vos tests ou bien de disposer d’un serveur Web. Dans le cadre d’un projet créer par Visual Studio, choisissez d’ajouter une application ASP.NET à votre projet et copier les assembly à télécharger dans le sous répertoire nommé Assemblies de Clientbin.

Le téléchargement de l’assembly

Dans un premier temps, il convient de récupérer en local l’assembly que l’on veut utiliser. Cette opération s’effectue par une requête http à l’aide de la classe WebClient. L’appel se fait en mode asynchrone afin de ne pas bloquer l’IHM.

WebClient downloader = new WebClient();

downloader.OpenReadCompleted +=
   
new OpenReadCompletedEventHandler(downloader_OpenReadCompleted);

downloader.OpenReadAsync(new Uri(assemblyName, UriKind.Relative));

L’instanciation de classe ne se fera qu’une fois le download fini. Son code doit être défini dans le gestionnaire d’événement OpenReadCompleted. Le soucis de ce template de code est que si le même code doit instancier différentes classe, on ne peut pas facilement lui transférer un contexte applicatif. Une solution élégante consiste à utiliser un delegate au lieu d’un gestionnaire d’évènement comme ceci :

WebClient downloader = new WebClient();

downloader.OpenReadCompleted +=
   
delegate(object s, OpenReadCompletedEventArgs args)
    {
        // code excuter une fois le tlchargement fini
    };

downloader.OpenReadAsync(new Uri(assemblyName, UriKind.Relative));

Le code de fin de téléchargement défini dans le delegate étant dans le même contexte que le téléchargement lui même, celui-ci dispose du contexte. Il suffit alors d’encapsuler ces lignes dans une méthode afin de passer en paramètre le nom de l’assembly et la classe à instancier.

private void DownloadAssemblyAndExecuteClass(string assemblyName, string controlClassName)
{
   
WebClient downloader = new WebClient();

   
downloader.OpenReadCompleted +=
       
delegate(object s, OpenReadCompletedEventArgs args)
        {
            
// assemblyName et controlClassName sont accessibles ici !!!
        
};

    downloader.OpenReadAsync(new Uri(assemblyName, UriKind.Relative));
}

L’instanciation de la classe

La dernière étape consiste à instancier la classe en chargeant dans un premier temps l’assembly. Cette opération est rendu possible grâce à la classe AssemblyPart de l’espace de nom System.Reflection. Sa méthode Load permet de charger une assembly à partir d’un Stream. Cela nous convient parfaitement puisqu’on reçoit un stream la fin du téléchargement de l’assembly par la classe WebClient. Une fois l’assembly en mémoire, l’instanciation d’une de ses classes s’effectue simplement par la méthode CreateInstance. Par conséquent, voici le code source complet qui insère l’instance du formulaire dans un conteneur de l’application nommé HostContainer :

private System.Reflection.Assembly loadedAssembly;

const string Directory = "Assemblies";
const string assemblyName = "CustomerFormContainer.dll";
const string controlClass = "CustomerFormContainer.CustomerForm";

private void Button_Click_Remote(object sender, RoutedEventArgs e)
{
   
// On passe le contexte applicatif

    DownloadAssemblyAndExecuteClass(Directory + "/" + assemblyName, controlClass);
}

private void DownloadAssemblyAndExeClass(string assemblyName, string controlClassName)
{
   
WebClient downloader = new WebClient();

    downloader.OpenReadCompleted +=
       
delegate(object s, OpenReadCompletedEventArgs args)
        {
           
AssemblyPart ap = new AssemblyPart();
            loadedAssembly = ap.Load(args.Result);
           
UserControl usercontrol =
                (
UserControl)loadedAssembly.CreateInstance(controlClassName);

            HostContainer.Children.Clear();
            HostContainer.Children.Add(usercontrol);
};

downloader.OpenReadAsync(new Uri(assemblyName, UriKind.Relative));
}

Et après ?

Que ce soit le chargement de l’assembly ou l’instanciation d’une classe, les opérations s’effectue uniquement à partir d’une chaine de caractère. On peut alors très facilement construire un framework consistant de chargement d’assembly à la volée. Assembly qui d’ailleurs peut être contenu dans un fichier xap comme le montre l’exemple de Pierre Lagarde ici : http://blogs.msdn.com/pierlag/archive/2008/10/27/chargement-d-assembly-externe-en-silverlight-2.aspx

Quant à moi, je montrerai dans prochain billet comment cacher de manière intelligente ces assembly en local pour encore plus minimiser les chargements au lancement d’une application Silverlight.

Windows 7, enfin une autre histoire…

Je me suis pris quelque jours de congés pour la période ces fêtes et j’en ai profité pour me faire une petit cadeau, un NetBook… et plus précisément le Lenovo S10. Il fallait bien que je m’occupe durant ces fêtes.

A peine rentré chez moi et après avoir testé la bonne exécution de la bête sous XP, je décide d’installer un Vista pour voir le comportement de la machine. Dans un premier temps, je l’ouvre pour remplacer son disque dur afin de ne pas perdre la configuration initiale. Ensuite, après une bonne heure d’installation de l’OS, de Office 2007, de Visual Studio et de Expression Blend, qu’elle ne fut pas ma surprise de voir fonctionner correctement un Vista sur une si petite configuration (processeur Atom 1,6Ghz, 1Go RAM et 80Go de HD). Mes tâches quotidiennes passant de la bureautique au démonstration de développement WPF et Silverlight sont complètement couvertes par cette configuration !

Du coup, je réinsère le disque dur d’origine dans le but d’installer une version toute fraîche de Windows 7 beta 1. A ce moment là, j’avais tiré une croix définitive sur l’installation de base XP à la vu des performances de Vista. Moins réactif que XP il faut l’avouer, mais largement acceptable.

Durant la phase d’installation de Windows 7, j’ai eu le drôle de sentiment que j’allais être agréablement surpris par cette béta. Il faut dire que l’expérience utilisateur a enfin fait  un pas dans cette version. Peu de question et reconnaissance de tous les drivers de la machine (mis à part le soft EnergyCut du Lenovo que je recommande d’installer par la suite pour voir visuellement la modification à l’aide du clavier des paramètres son, luminosité, Wifi On/Off, etc). Comme je venais de passer de XP à Vista puis à Windows 7 dans un temps assez court, je me suis très vite aperçu à quel point Windows 7 surpasse Vista dans toutes les tâches… et aussi à mon avis XP...

Cela fait maintenant 3 semaines que j’utilise mon Lenovo S10 avec Windows 7 et je n’ai eu aucune mauvaise surprise, bien au contraire. J’ai été agréablement surpris par les petites retouches de l’interface dont je ne peux plus me passer, la gestion des disques virtuelles, les outils de bases qui sont maintenant réellement opérationnels (une vraie calculatrice, un vrai Paint, un Wordpad qui relit des docx..), etc. Mais principalement je retiens qu’une seule impression de cet OS : Le fait que la machine semble toujours disponible là où l’impression d’attente était présente sur les deux précédents OS…

Vous l’aurez compris, je suis conquis. Aujourd’hui j’utilise quotidiennement mon Lenovo avec Windows 7 dans toutes les tâches hormis l’encodage de la vidéo qui met facilement à genou un Atom 1,6Ghz... 

Si vous voulez avoir un très bon aperçu des nouveautés de Windows 7, je ne peux que vous recommander le billet de Tim Sneath : http://blogs.msdn.com/tims/archive/2009/01/12/the-bumper-list-of-windows-7-secrets.aspx

Bonne lecture.

Using the Silverlight 1.0 MediaElement for live streaming

If you want to create a Live TV player with Silverlight, perhaps are you going to face with some troubles if you want to switch from a live stream to another. The problem comes if you try to use Stop and Play methods. Instead, you have to use the AutoPlay property

Here is a sample :

...
    media = rootElement.findName("mediaElement");   
    media.addEventListener("MediaOpened", Silverlight.createDelegate(this, this.handleMediaOpened));
...

setMediaElementSource : function(sender, url) {
    this.startWaiting(sender); // start an animation
    media.AutoPlay="False"
    media.Source = url ;
   media.AutoPlay="True"
},

handleMediaOpened: function(sender, eventArgs)
{
    this.stopWaiting(sender); // stop the animation
},

startWaiting : function(sender)
{
    sender.findName("StoryboardWaiting").begin();
},


stopWaiting : function(sender)
{
    sender.findName("StoryboardWaiting").stop();
}

Page view tracker