Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

Silverlight 3 : Gestion des cookies

Silverlight propose un espace de stockage privé pour chaque application sur la machine cliente. Cet espace s'appelle l'Isolated Storage (stockage isolé, car protégé et isolé du reste de la machine cliente). C'est dans cet espace qu'il est conseillé de sauvegarder les données propres à l'application (j'y reviendrai dans un prochain billet). Toutefois on peut amené pour certaines informations à préférer le stockage sous la forme de Cookies traditionnels. On peut aussi avoir besoin de lire certains cookies posés par l'éventuelle application hôte en ASP.NET par exemple.

Quelles que soient les raisons, il peut donc s'avérer utile de manipuler les cookies depuis une application Silverlight.

L'application exemple ci-dessous vous permet de tester en live cette fonctionnalité :

[silverlight:source=/SLSamples/Cookies/Cookies.xap;width=380;height=322]

Techniquement, et après avoir ajouté à votre code le using du namespace "System.Windows.Browser", il suffit pour créer (ou modifier) un cookie d'appeler la méthode SetProperty de HtmlPage.Document :

   1:  private bool setCookie(string key, string value)
   2:          {
   3:              if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value))
   4:              { return false; }
   5:              DateTime dt = calExpiry.SelectedDate ?? DateTime.Now 
   6:                  + new TimeSpan(1, 0, 0);
   7:              string s = key.Trim() + "=" + value.Trim() 
   8:                  + ";expires=" + dt.ToString("R");
   9:              HtmlPage.Document.SetProperty("cookie", s);
  10:              return true;
  11:          }

Pour la lecture on accède à la chaîne "Cookies" de HtmlPage.Document qu'on peut ensuite traiter pour séparer chaque cookie :

   1:  private string getCookie(string key)
   2:          {
   3:              string[] cookies = HtmlPage.Document.Cookies.Split(';');
   4:              foreach (string cookie in cookies)
   5:              {
   6:                  string[] pair = cookie.Split('=');
   7:                  if (pair.Length == 2)
   8:                  {
   9:                      if (pair[0].ToString() == key)
  10:                          return pair[1];
  11:                  }
  12:              }
  13:              return null;
  14:          }

Bref, rien de bien compliqué mais qui pourra vous servir dans certains cas.

Le code source du projet (Blend 3 de préférence, sinon VS 2008 + SL3) : Cookies.zip (62,65 kb)

Stay Tuned !

 

Silverlight 3 (+WPF) : Hatching Effect gratuit + Sources

Les pixel shaders de Silverlight 3 fournis "out of the box" ne sont que deux : le drop shadow et le blur. Mais comme cela était prévisible de nombreux programmeurs exercent leur talent en créant de nouveaux effets...

Forcément l'équipe Microsoft de la suite Expression est très bien placée pour ce genre d'exercice et elle nous propose via son blog un effet de crayonnage assez bien fait. Le tout avec install pour automatiquement voir l'effet dans les palettes de Blend 3 mais aussi avec le code source pour l'étudier et faire ses propres effets.

Le mieux est de vous rendre directement sur le blog de l'équipe Expression, et plus particulièrement sur le billet présentant le Hatching effect. Source et install sont téléchargeables depuis le billet.

A noter, l'effet fonctionne aussi avec WPF selon ce qui est dit mais je n'ai testé que sous Silverlight.

Stay Tuned !

Suite Expression 3 finale disponible !

La suite Expression 3 contenant notamment l'extraordinaire Blend 3 est disponible en téléchargement ... pour les chanceux abonnés à MSDN.

Pour les autres je suppose que le produit peut désormais être acheté chez Microsoft, au pire il s'agit d'une question de jours seulement.

Bon, je vous laisse, je viens de finir le download et je désinstalle Blend 3 beta le temps d'écrire ce billet et je vais maintenant installer tout ça !

Miam ! ... euhh Stay Tuned je voulais dire !

Silverlight 3 : Les Pixel shaders (effets bitmap) et l'accélération GPU

L'une des grandes nouveautés de Silverlight 3 c'est le support de l'accélération graphique. L'application principale se trouve déchargée de certaines tâches qui sont routées vers le GPU de la carte graphique. Mais attention, l'accélération GPU de Silverlight 3 ne fait pas tout comme sa grande soeur sous WPF (qui utilise DirectX et toutes ses ficelles pour accélérer le traitement vidéo). On aurait pu croire que les effets bitmaps (pixel shaders) de WPF qui viennent d'être portés sous Silverlight 3 utilisent l'accélération GPU, en réalité il n'en est rien. Mais cela n'enlève rien à ces nouveaux effets parfaitement utilisables pour enrichir le visuel d'une application et dont je vais vous parler maintenant...

Quelques mots sur l'accélération GPU : Même si ce n'est pas le sujet du présent billet, il s'agit d'une nouvelle feature très intéressante de SL3. On a tendance hélas (et j'ai été le premier à me faire "avoir") à trop vite faire le parallèle avec WPF et à transposer ce que fait l'accélération sous ce dernier. En fait, le support de l'accélération GPU de SL3 est pour l'instant assez limité et ne se met en route que de façon volontaire. Elle ne s'applique pas aux effets bitmaps ni aux nouveaux Codecs vidéos qui restent traités par le CPU. Malgré tout le système d'accélération graphique peut rendre d'immense service, dans certains de mes tests sur l'animation d'images assez grandes j'ai pu voir mon PC de test passer de 88% d'utilisation CPU (double coeur Asus plutôt rapide) à moins de 4% ! Ce qui est énorme. Mais pour profiter de l'accélération il faut aboslument en connaître le fonctionnement et les limitations. Je vous invite ainsi à lire l'excellent billet de Andras Verlvart sur la question. Il est assorti d'une application exemple qui permet de bien voir l'effet des différentes possibilités d'accélération et leur impact sur le CPU et le GPU. Cet article est en anglais, pour ceux qui préfère la lecture en français, David Rousset a écrit un billet qui fait le point sur cette même question.

Les Pixel Shaders 

Par défaut Silverlight 3 est fourni avec deux effets : le blur (flou) et le drop shadow (ombre portée). Mais on trouve sur CodePlex un très beau projet offrant toute une série de nouveaux effets comme le swirl ou l'emboss (WPF Effects Library pour WPF et Silverlight). Grâce au SDK Directx et au langage HSL il possible de développer ses propres effets.

L'exemple ci-dessous illustre mon propos : la fenêtre principale est décorée d'une magnifique photo d'éclair (copyrigthée par moi-même) sur laquelle un flou peut être appliqué grâce à un slider se trouvant dans une petite fenêtre semi transparente sur laquelle est appliqué un drop-shadow.

Vous remarquerez que la petite fenêtre en question peut être déplacée par drag-drop grâce à une autre nouveauté de Silverlight 3 : les behaviors (comportements), sorte de petits bouts de code compilés qu'on peut "jeter" sur n'importe quel contrôle pour lui offrir le dit comportement, ici un déplacement par drag-drop. Le tout sans une ligne de C#. Le slider a été templaté "à l'arrache" mais il a été templaté tout de même :-). Autre nouveauté de Silverlight 3 qui est ici démontrée : le databinding entre éléments d'interface, ainsi le texte indiquant la quantité de flou appliquée est directement lié à la propriété Value du Slider. Pour formater cette valeur un convertisseur a été ajouté.

Bref, une petite application vite fait pour montrer les Pixel Shaders, mais pas seulement...

Le mieux étant maintenant de jouer avec et de télécharger le projet (VS2008 + SL3 toolkit ou Blend 3 de préférence) : PixelShader.zip (168,29 kb)

[silverlight:source=/SLSamples/PixelShader/PixelShader.xap;width=550;height=480]

Et Stay Tuned !

nota: cet article du 28 juillet 2009 a été mis à jour le  3 août à propos de l'accélération GPU.

Silverlight : Application transparente

Il est tout à fait possible de rendre une application (ou une fenêtre) Silverlight transparente, c'est à dire que son contenu apparaîtra sur la couleur de fond du site hôte. Cela peut s'avérer très utile pour des petits morceaux de Silverlight placés sur un site Html ou Asp.net, pour créer une barre de menu par exemple. Si la charte couleur du site est modifiée il ne sera pas nécessaire de modifier et recompiler la ou les applications Silverlight.

Pour arriver à ce résultat il faut faire deux choses simples dont la syntaxe dépend de la nature de la page où s'insère le plugin (ASP.NET ou HTML)

exemple ASP.NET :

<asp:Silverlight PluginBackground="Transparent" Windowless="true" ID="Menu" runat="server" 
Source="~/ClientBin/Menuxap" MinimumVersion="xxxxx"  />  

exemple HTML :

<object data="data:application/x-silverlight," type="application/x-silverlight-2-b2" > 
<param name="source" value="ClientBin/Menu.xap"/> 
<param name="onerror" value="onSilverlightError" /> 
<param name="pluginbackground" value="Transparent" /> 
<param name="windowless" value="true" />  
</object>   

Les deux paramètres importants étant : PluginBackgrounf et Windoless .

Par défaut une application Silverlight occupe 100% de la fenêtre hôte, dans le cas d'une barre de menu ou d'un autre type de fenêtre intégré à une page ASP.NET/HTML on ajoutera donc dans les balises la déclaration de la hauteur et de la largeur exacte qu'on souhaite réserver pour le plugin. Bien entendu le contenu de l'application Silverlight doit être dépourvu d'arrière plan, cela va sans dire, sinon, transparence ou non, c'est lui qui sera affiché et non le background de la page hôte...

 

Silverlight 3 : La multi-sélection

Parmi les petites évolutions de Silverlight 3 qui ne méritent pas un article de fond mais qu'il faut noter tellement elles simplifient les choses, j'apprécie le support de la multi sélection dans les ListBox.

La nouvelle propriété s'appelle sans malice : SelectionMode et elle peut prendre les valeurs suivantes : Single, Multiple, Extended. En mode Single on retrouve le comportement par défaut mono sélection. Les deux autres modes permettent d'accéder au comportement multi sélection. En mode Multiple la sélection s'opère par le clic sur un item, en enfonçant Ctrl ou Shift. Le mode Extended fait que le Shift permet de sélectionner des étendues.

Jouez avec notre ami Casimir dans l'exemple ci-dessous, et grâce à la nouvelle ListBox Silverlight 3 confectionnez votre propre Gloubiboulga en partant de la recette originale et de ses options (pour les plus gourmands !) :

[silverlight:source=/SLSamples/MultiSelect/MultiSelect.xap;width=411;height=203]

Bon appétit, et... Stay Tuned !

Silverlight 3 : Styles Cascadés (BasedOn Styles)

Toujours dans ma petite série sur les nouveautés de Silverlight 3 je vais vous présenter aujourd'hui une feature plaisante : les styles cascadés.

En soi rien de nouveau à l'ouest puisque c'est le principe même des feuilles de styles CSS (qui y puisent d'ailleurs leur nom). Mais le CSS s'applique à quelques éléments simples HTML alors que là nous parlons de styles Silverlight, c'est à dire d'objet complexes pouvant définir tout un visuel, animations comprises.

[silverlight:source=/SLSamples/BasedOnStyle/BasedOnStyle.xap;width=405;height=150]

Dans l'application Sivlerlight 3 ci-dessus (fonctionnelle, ce n'est pas une capture écran), vous voyez 4 boutons. Tous sont des boutons standard du framework.

  • Le premier, intitulé "Base SL" possède le style Silverlight par défaut
  • Le second, "Normal" est décoré par le style "BoutonNormal"
  • Le troisième "Gros" est décoré par le style "BoutonGros"
  • Et le quatrième "Alarme" est décoré par le style "BoutonGrosAlarme"

Visuellement c'est plutôt moche, je vous l'accorde, mais le but du jeu est de voir l'effet du cascading styling...

Le style "BoutonNormal" est défini comme suit :

<Style x:Key="BoutonNormal" TargetType="Button">
     <Setter Property="Width" Value="90" />
     <Setter Property="Height" Value="30" />
     <Setter Property="HorizontalAlignment" Value="Left" />
     <Setter Property="VerticalAlignment" Value="Bottom" />
     <Setter Property="BorderThickness" Value="2"/>
</Style>

Là où les choses deviennent plus intéressantes, c'est dans le style "BoutonGros" ci-dessous où l'on voit apparaître l'attribut BasedOn qui permet de fonder le style courant sur celui qu'on indique :

<Style x:Key="BoutonGros" 
         BasedOn="{StaticResource BoutonNormal}"
         TargetType="Button">
  <Setter Property="Width" Value="180" />
  <Setter Property="Height" Value="60" />
  <Setter Property="FontFamily" Value="Comic Sans MS"/>
</Style>

Enfin, le dernier style se fonde lui-même sur le précédent par le même mécanisme, le niveau de cascading n'étant pas limité. On peut voir notamment que le changement de famille de fonte introduit dans le style "BoutonGros" s'est propagé au style "BoutonGrosAlarme" (fonte Comic).

<Style x:Key="BoutonGrosAlarme" 
         BasedOn="{StaticResource BoutonGros}"
         TargetType="Button">
  <Setter Property="Width" Value="160" />
  <Setter Property="Height" Value="40" />
  <Setter Property="FontSize" Value="18"/>
  <Setter Property="FontWeight" Value="Bold"/>
  <Setter Property="Foreground" Value="Red"/>
  <Setter Property="BorderThickness" Value="4"/>
  <Setter Property="BorderBrush" Value="#FFFF0202"/>
</Style>

Voilà, c'est tout simple, mais cela peut radicalement simplifier la création de gros templates pour des applications. Tous les avantages du Cascading Style Sheet de HTML dont l'intérêt ne se démontre plus, mais appliqué à des objets et à la sophistication de Silverlight. Que du bonheur...

Bon Styling,

...Et Stay Tuned !

Silverlight 3 : L'Element Binding

L’Element Binding est une nouvelle feature de Silverlight 3 déjà présente sous WPF.

L’Element Binding définit la capacité de lier les propriétés des objets entre eux sans passer par du code intermédiaire. Cette possibilité existait déjà sous WPF, on la retrouve désormais sous SL3.

Pour simplifier prenons l’exemple d’un panneau d’information, par exemple un Border avec un texte à l’intérieur. Imaginons que l’utilisateur puisse régler l’opacité de cette fenêtre par le biais d’un Slider. (ci-dessous l'application exemple pour jouer en live).

[silverlight:source=/SLSamples/EBinding/EBinding.xap;width=452;height=240]

On place quelques éléments visuels sous le Border (ici des rectangles) afin de mieux voir l’effet du changement d’opacité.

Trois méthodes s'offre à nous pour régler le lien entre le Slider et l'opacité du Border. J'appellerai la première "méthode à l'ancienne", la seconde "méthode du certifié" et la troisième "méthode Silverlight 3". Les trois ont leur intérêt mais si vous êtes très pressé vous pouvez directement vous jeter sur la 3eme solution :-)

Méthode 1 dite « à l’ancienne »

Le développeur Win32 habitué aux MFC ou à des environnements comme Delphi aura comme réflexe immédiat d’aller chercher l’événement ValueChanged du Slider et de taper un code behind de ce type :

MonBorder.Opacity = MonSlider.Value ;

Ça a l’avantage d’être simple, efficace, de répondre (apparemment) au besoin et de recycler les vielles méthodes de travail sans avoir à se poser de questions…

Méthode 2 dite « du certifié »

Ici nous avons affaire à un spécialiste. Son truc c’est la techno, suivre les guide-lines et écrire un code qui suit tous les dogmes de l’instant est un plaisir intellectuel. Parfois ses solutions sont un peu complexes mais elles sont belles et à la pointe de la techno !

Conscient que la solution « à l’ancienne » a un petit problème (en dehors d’être trop simple pour être « belle », elle est one way, le slider modifie l'opacité du border mais l'inverse ne fonctionne pas) il va chercher une solution objet élégante répondant à l’ensemble des cas possibles couvrant ainsi le two way, considération technique trop technophile pour le développeur du cas précédent.

Ici forcément ça se complique. C’est techniquement et intellectuellement plus sexy que la méthode « à l’ancienne » mais cela réclame un effort de compréhension et de codage :

Il faut en fait créer un objet intermédiaire. Cet objet représente la valeur du Slider auquel il est lié lors de son instanciation. Quant à l’objet Border, sa propriété Opacity sera liée par Data Binding standard à l’objet valeur.

Voici le code de la classe de liaison :

public class ValueBinder : INotifyPropertyChanged
       {
             public event PropertyChangedEventHandler PropertyChanged;
             private Slider boundSlider;
             public ValueBinder(Slider origine)
             {
                    boundSlider = origine;
             }
 
             public double Value
             {
                    get { return boundSlider==null?0:boundSlider.Value; }
                    set {
                           if (PropertyChanged!=null)
                                  PropertyChanged(this,
                                    new PropertyChangedEventArgs("Value"));
                           boundSlider.Value = value;
                    }
             }
       }

Cette classe, ou plutôt l’une de ses instances, servira a représenter la valeur courante du Slider. Ce dernier est lié à l’instance lors de la création de cette dernière (voir le constructeur de la classe ValueBinder ci-dessus).

Comment utiliser cette classe ?

La première chose est qu’il faut en créer une instance, cela peut se faire dans le code XAML ou bien dans le code behind de la façon suivante (dans le constructeur de la page par exemple) :

var valueBinder = new ValueBinder(slider);

Maintenant il suffit dans le code XAML de lier les deux objets à la valeur de la classe intermédiaire, par Data Binding :

Côté Slider, le code est :

<Slider x:Name="slider"Value="{Binding Value, Mode=TwoWay}"/> 

Côté Border :

<Border x:Name="borderInfo"Opacity="{Binding Value, Mode=TwoWay}"> 

Ne reste plus qu’à rendre visible l’objet intermédiaire par exemple en en faisant la valeur courante du DataContext de l’objet LayoutRoot :

LayoutRoot.DataContext = valueBinder;

Et voilà ! Ne reste plus qu’à compiler et vous le plaisir de voir que l’opacité du Border change bien lorsque le Slider est déplacé.

La chaîne est la suivante : la modification de la position du Thumb entraîne dans le composant Slider la modification de la valeur de la propriété Value. Comme celle-ci est liée par Data Binding TwoWay à la propriété Value de l’objet intermédiaire cette propriété va se trouver modifiée dans le même temps. Comme le Setter de la propriété notifie le changement de valeur de la propriété (la classe implémente INotifyPropertyChanged) et comme la propriété Opacity du Border est elle aussi liée par Data Binding à la propriété Value de l’objet intermédiaire, le Border sera « prévenu » du changement de valeur et sa propriété Opacité sera immédiatement modifiée pour recevoir la valeur courante de Value de l’objet intermédiaire ! C’est pas fun tout ça ? (hmmm j’en vois un qui suit pas là bas au fond… !).

Vous allez me dire, TwoWay, on veut bien te croire mais on ne le voit pas là … Pour l’instant cela se comporte exactement comme la première solution, juste qu’il faut avoir un niveau de certifié pour comprendre…

C’est pas faux. C’est pourquoi je vais maintenant ajouter un petit bout de code pour faire varier la valeur de la propriété Opacity du Border. Le plus simple est de gérer la roulette de la souris dans le Border :

<Border x:Name="borderInfo"MouseWheel="Border_MouseWheel"> 

Et dans le code behind :

private void Border_MouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e) 
             { 
                    borderInfo.Opacity += e.Delta/1000d; 
                    e.Handled = true;
             }

Il suffit maintenant de faire rouler la molette au dessus du Border pour en changer l’opacité. Le TwoWay ? Regardez bien : le curseur du Slider avance ou recule tout seul… Pour éviter que la page HTML contenant le plugin Silverlight ne se mette à scroller il faut bien entendu indiquer que l'événement est géré (Handled=true) ce qui est fait dans le code ci-dessus.

Cette solution est élégante, complète mais complexe. Elle reste l’approche à préconiser dans tous les cas du même type car, on le voit bien, si la première solution est simple, elle n’est pas complète. Complexifier par plaisir est un mauvais réflexe, mais ne pas voir qu’une solution est trop simpliste est aussi un défaut qu’il faut fuir !

Bref, sous Silverlight 2 la solution présentée ici est une bonne solution. Sous Silverlight 3 qui supporte le Binding direct entre éléments (comme WPF) nous allons pouvoir faire plaisir à la fois au développeur du premier cas et à celui du second :

Méthode 3 dite « Silverlight 3 »

Comment marier le reflexe (plutôt sain) du premier développeur de notre parabole de vouloir faire vite et simple avec l’exigence intellectuelle (tout aussi saine) du second qui implique de faire « complet » ?

Pour illustrer l’Element Binding de façon simple, prenons un Scrollbar en mode horizontal et un Slider en mode vertical.

Et regardons le code XAML de leur déclaration :

<ScrollBar x:Name="scrollA"Value="{Binding Value, ElementName=sliderB, Mode=TwoWay}"/> 
 
<Slider x:Name="sliderB"Value="{Binding Value, ElementName=scrollA, Mode=TwoWay}" /> 

Et c’est tout ce qu’il y a à faire pour obtenir une solution complète, élégante, sans code behind et très facile à mettre en œuvre ! Merci Silverlight 3 !

En début de billet vous pouvez jouer avec les deux dernières implémentations (je n’ai pas implémenté la méthode 1) .

Vous pouvez aussi télécharger le code du projet (Blend 3 ou VS2008 avec les extensions SL3) : elementBinding.zip (61,43 kb)

Pour d'autres nouvelles, Stay Tuned !

Silverlight 3 : Nouveau contrôle DataForm et Validation des données

Je continue ma petite série sur les nouveautés de Silverlight 3. Au menu un composant des plus intéressant et un nouveau système de validation.

Le composant s'appelle DataForm, il est en quelque sorte le pendant mono enregistrement du composant DataGrid. Avec cette dernière on montre plusieurs enregistrements à la fois, avec la DataForm on présente les données d'une seule fiche. On conserve malgré tout la possibilité de navigueur de fiche en fiche, et le composant est hautement personnalisable grâce aux styles et templates.

Imaginons une petite fiche permettant de créer un login : pseudo, e-mail et mot de passe sont le lot de ce genre de cadres de saisie. Pour les besoins de la démo commençons par créer une classe représentant l'ensemble des informations à saisir (voir le code en fin de billet).

Rien d'exceptionnel ici donc, juste une petite classe. Mais vous remarquerez plusieurs choses :

  • Les propriétés sont décorées d'attributs qui permettent de modifier notamment l'affichage des labels dans la DataForm, un nom interne de propriété n'est pas forcément adapté pour une lecture par l'utilisateur final.
  • Les propriétés sont décorées de l'attribut Required. Autre particularité pour la DataForm : certains champs peuvent être obligatoires.      

Dans le code ci-dessous chaque propriété prend en charge sa validation : elle lève une exception dès que la valeur passée n'est pas conforme à celle attendue. Il existe d'ailleurs un doublon fonctionnel dans ce code : la présence de la méthode CheckNull qui s'assure qu'une propriété n'est pas vide, et l'attribut Required. En l'état c'est la méthode CheckNull qui prend le dessus, on pourrait donc supprimer l'attribut.


Il existe bien d'autres attributs pour la DataForm et le propos de ce billet n'est pas de tous les détailler, mais il est important de noter comment le code peut prévoir certains comportements qui seront reportés sur l'interface utilisateur sans réellement interférer avec elle... subtile.

Regardons maintenant le code XAML de la page affichée par Silverlight (en fin de billet). 

Tout d'abord vous remarquerez que l'instance de LoginInfo n'est pas créée dans le code C# mais sous forme de ressource dans la fiche, en XAML.
Ensuite nous définissions une balise DataForm dont l'item courrant est lié à l'instance de LoginInfo.

Et c'est tout. Pour la décoration j'ai ajouté un bouton "ok" qui accessoirement lance la valitation totale de la fiche. Ne saisissez rien et cliquez dessus : vous verrez apparaître le cadre des erreurs avec la liste de toutes les validations qui ont échouées. Bien entendu l'aspect de ce cadre est templatable aussi.

Le mieux est de jouer avec l'application de test ci-dessous:



Vous pouvez aussi télécharger le code du projet (à utiliser sous Blend 3 ou VS2008 avec les extensions SL3): SL3DataValidation.zip (60,40 kb)


[silverlight:source=/SLSamples/Validation/DataValidation.xap;width=400;height=320]

A noter : la présence du petit symbole info, il répond à l'attribut Description prévu dans le code de la classe et permet d'informer l'utilisateur.
Vous remarquerez aussi qu'en passant d'un champ à un autre les champs invalidés sont décorés par une lisière rouge dont un coin est plus marqué : cliquez sur ce dernier et vous obtiendrez le message d'erreur avec sa petite animation. L'aspect de ce cadre ainsi que l'animation sont bien entendu modifiables à souhait.

Stay Tuned pour d'autres nouveautés de SL3 !

 

Code de la classe LogInfo :

 

   1:  public class LoginInfo : INotifyPropertyChanged
   2:      {
   3:          private string loginName;
   4:          
   5:          [Required()]
   6:          [Display(Name="Login name:",Description="Votre login personnel.")]
   7:          public string LoginName
   8:          {
   9:              get { return loginName; }
  10:              set 
  11:              {
  12:                  checkNull(value);
  13:                  loginName = value.Trim();
  14:                  dochange("LoginName");
  15:              }
  16:          }
  17:          
  18:          
  19:          private string email;
  20:          
  21:          [Required()]
  22:          [Display(Name="e-mail:",Description="Adresse mail pour vous joindre.")]
  23:          public string Email
  24:          {
  25:              get { return email; }
  26:              set 
  27:              {
  28:                  checkNull(value);
  29:                  checkMail(value);
  30:                  email = value.Trim();
  31:                  dochange("Email");
  32:              }
  33:          }
  34:          
  35:          private string password;
  36:          
  37:          [Required()]
  38:          [Display(Name="Mot de passe:",Description="Votre mot de passe de connexion.")]
  39:          public string Password
  40:          {
  41:              get { return password; }
  42:              set 
  43:              {
  44:                  checkNull(value);
  45:                  password = value.Trim();
  46:                  dochange("Password");
  47:              }
  48:          }
  49:          
  50:          private string passwordCheck;
  51:          
  52:          [Required()]
  53:          [Display(Name="Contrôle:",Description="Retapez ici votre mot de passe.")]
  54:          public string PasswordCheck
  55:          {
  56:              get { return passwordCheck; }
  57:              set 
  58:              {
  59:                  checkNull(value);
  60:                  passwordCheck = value.Trim();
  61:                  if (string.Compare(password,passwordCheck)!=0)
  62:                      throw new Exception("Les mots de passe diffèrent !");
  63:                  dochange("PasswordCheck");
  64:              }
  65:          }
  66:          
  67:          private void checkMail(string value)
  68:          {
  69:              string pattern = @"^(([^<>()[\]\\.,;:\s@\""]+" 
  70:                          + @"(\.[^<>()[\]\\.,;:\s@\""]+)*)|(\"".+\""))@" 
  71:                          + @"((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" 
  72:                          + @"\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+" 
  73:                          + @"[a-zA-Z]{2,}))$";
  74:                    Regex regMail = new Regex(pattern);
  75:                   if (!regMail.IsMatch(value)) throw new Exception("E-mail non valide !");
  76:          }
  77:          
  78:          private void checkNull(string value)
  79:          { 
  80:              if (string.IsNullOrEmpty(value)) throw new Exception("Ne peut être vide !");
  81:          }
  82:   
  83:          #region INotifyPropertyChanged Members
  84:   
  85:          public event PropertyChangedEventHandler PropertyChanged;
  86:          private void dochange(string property)
  87:          {
  88:              if (PropertyChanged!=null) PropertyChanged(this,new PropertyChangedEventArgs(property));
  89:          }
  90:   
  91:          #endregion
  92:      }

le code XAML de la fiche :

 

   1:  <UserControl
   2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:      xmlns:dataFormToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
   5:      xmlns:local="clr-namespace:DataValidation"
   6:      x:Class="DataValidation.MainPage"
   7:      Width="300" Height="320">
   8:   
   9:      <UserControl.Resources>
  10:       <local:LoginInfo x:Key="loginRec"  />
  11:      </UserControl.Resources>
  12:   
  13:      <StackPanel x:Name="LayoutRoot">
  14:          <dataFormToolkit:DataForm 
  15:              x:Name="PwForm" 
  16:              CurrentItem="{StaticResource loginRec}" 
  17:              Foreground="Black" 
  18:              Height="292" 
  19:              VerticalAlignment="Top" 
  20:              TabNavigation="Cycle"/>
  21:          <Button 
  22:              Content="Ok" 
  23:              VerticalAlignment="Center" 
  24:              HorizontalAlignment="Center" 
  25:              Click="Button_Click"/>
  26:      </StackPanel>
  27:  </UserControl>

Exemple Silverlight 3 : Projection 3D

Silverlight 3 est arrivé avec son lot de nouveautés, toutes sont intéressantes et poussent encore plus loin la limite du possible. Dans le même temps la convergence avec WPF se fait de plus en plus forte.

Aujourd'hui je vais vous parler de la projection 3D. Ce qu'on appelle de la "2,5D" car ce n'est déjà plus de la 2D mais ce n'est pas encore de la vraie 3D (qui implique la manipulation d'objets vectoriels 3D comme WPF sait le faire). Sous Silverlight 3, la 2,5D est un groupe de transformation qui s'ajoute à celui déjà présent (et permettant les translation, le skew, les rotations, etc). Ce nouveau groupe se présente globalement de la même façon (en tout cas sous Blend 3) mais les effets sont différents puisqu'il s'agit de créer des effets de perspectives 3D avec les objets 2D de Silverlight.

A quoi cela peut-il bien servir ?

A plein de choses ! Au niveau graphique et visuel s'entend.

Pour illustrer tout cela voici un exemple qui montre comment on peut animer une petite fiche d'information qui donne l'impression d'avoir deux faces, comme une carte de jeu par exemple : Exemple SL3 Projection. Vous pouvez aussi directement jouer avec l'exemple qui s'affiche ci-dessous (je teste en même temps l'excellent plugin Silverlight pour BlogEngine) :

[silverlight:source=/SLSamples/3DProjection/3DProjection.xap;width=350;height=446]

Je me suis inspiré de l'exemple de Jesse Liberty (que j'appelle affectueusement Droopy en raison de la tonalité de sa voix) un grand fan de Silverlight chez MS qui propose des tas de tutors et autres vidéos. En revanche Jesse est un gars qui travaille un peu "à l'ancienne", et pour arriver au résultat il faut deux vidéos d'explications car tout est tapé à la main en XAML. Cela a l'avantage de bien détailler l'astuce utilisée, mais ce n'est pas ce que je vise. Personnellement je veux arriver à tout faire sous Blend car on ne forme pas des infographistes en leur expliquant les arcanes de XAML mais en leur montrant comment on arrive au résultat interactivement. Et justement je prépare une série de vidéos de formation autant pour les développeurs que pour les infographistes...

J'ai donc totalement refait l'exemple sous Blend 3, sans une ligne de C# ni aucune de XAML tapée à la main (car forcément, il y a du XAML mais c'est Blend qui s'en occupe). J'arrive d'ailleurs à obtenir le même effet que Jesse en deux storyboards au lieu de 3 et en utilisant un Behavior pour déclencher les animations depuis les boutons au lieu de code behind C#. Je me suis même offert le luxe d'utiliser les nouveaux modes de EaseIn/Out qui permettent d'obtenir des mouvements plus "organiques" (effets de rebonds ou d'élastique par exemple).

Comme il n'y a rien dans ce projet d'autre que deux timelines, plutôt qu'un long discours je vous propose de charger le projet exemple (VS 2008 avec toutes les extensions Silverlight 3 ou bien mieux, ouvrez le projet directement dans Blend 3) : 3DProjection.zip (61,42 kb)

En deux mots, l'astuce consiste à avoir deux fiches identiques au niveau de leur forme extérieure. L'une est la face A, l'autre la face B. Le contenu des deux fiches est totalement libre.

Au début la fiche A est visible "à plat", "normalement" donc. Sur l'appui du bouton "aide" (simple exemple) l'animation FlipToBack est lancée. Elle consiste à appliquer une transformation perspective sur l'axe Y pour donner l'impression que la fiche tourne. Pour que la fiche B ne soit pas visible durant cette phase, elle a subit en début d'animation une simple translation pour l'amener en dehors de l'espace de l'application (par exemple en position 1000 sur l'axe Y).

Au moment où la fiche A passe à 90 degrés, c'est à dire quand elle est vue par la tranche, et comme elle n'a aucune épaisseur, elle disparait visuellement. C'est à ce moment précis que la magie s'opère : on fait faire une rotation à la fiche B pour qu'elle soit sur sa tranche aussi et on l'amène à la place de la fiche A (en annulant la translation sur Y de B) et dans le même temps on fait une translation de 1000 sur Y de la fiche A. Les keyframes utilisées pour cette substitution sont de type HoldIn, c'est à dire qu'il n'y a pas de transition douce avec l'état précédant, tout est instantané. Maintenant que la fiche B est à la place de la fiche A, on peut continuer l'animation de B pour qu'elle s'affiche. Le "spectateur" est dupé : durant la microseconde où la fiche A était vue par la tranche nous lui avons substitué la fiche B vue sous le même angle. Le début de l'animation fait tourner A, alors que la seconde partie de l'animation fait tourner B, mais on a l'impression visuelle que c'est la même fiche qui tourne et qu'on en découvre le dos...

Pour revenir de la page B à la page A, il suffit de créer une seconde timeline qui reprend le même principe mais qui fait les choses dans l'autre sens...

Krafty non ?

Amusez vous bien avec l'exemple et surtout...

Stay tuned !