04/11/2012

[Surface] Premières impressions


Commandée le jour même de l'annonce de la sortie officielle de Windows 8, 3 jours ont suffit pour recevoir ma Surface. Petite précision, le modèle testé est la version WinRT 32 Go avec un Clavier "Touch Cover". La version sans le clavier portait le délai de livraison à 3 semaines.

Donc avec presque un semaine de pratique, je vous livre mes impressions.

Le Hardware



La Surface

Dès la saisie, on sent la surface présente de part son poids. Equilibrée, elle se laisse prendre en main sans déconvenue. A noter la présence d'une prise USB. Chez certains concurrents ce genre de détails n'est pas pris en compte.

D'autre part et personnellement, je n'ai jamais réussi à utiliser une couverture d'iPad pour faire tenir le devise. Avec la surface, pas de souci, même pour les mecs comme moi y arrivent. Le support se sort et se range facilement.

Côté finition, on est sur un objet épurée, comme le sont presque toute les tablettes. La jointure coque, écran laisse présager une certaine solidité dans le temps mais à voir.

Le Touch Cover

Le Touch Cover était vraiment l'élément technique de la surface qui m'intriguait le plus. Et ma première réaction a été vraiment de me dire qu'ils avaient bien bossé. Mais très vite je suis resté dubitatif qu'en au ressenti sur les touches.

Dès la première utilisation, le fait de ne pas avoir de retour sensitif sur les touches m'a vraiment perturbé. Après plusieurs heures d'utilisation avec l'ensemble de la tablette, on constate un véritable contraste entre la fluidité et la réactivité qui est à mon sens excellente (à noter aussi performante que sur Windows Phone) sur la tablette et l'utilisation de certaines touches du clavier qui nécessite d'appuyer un peu plus franchement.

En écrivant ces lignes, je me rends compte qu'au final, à part en protection d'écran, je n'ai plus utilisé le Touch Cover depuis quelques jours. En revanche, mon entourage lui a très vite adopté le clavier, notamment avec le côté rassurant du Touch Pad pour une utilisation souris.

l'OS

Donc, je ne vais pas faire un listing des nouvelles fonctionnalités de Windows 8, d'autres sites spécialisés ont déjà fait ça et certainement mieux que moi. Pour avoir découvert Windows 8 lors de sa première version béta, la plus grande surprise à résider dans l'efficacité du devise à mettre l'OS.

En revanche, un point qui a mon sens risque de coincer avec le grand public est le faible espace disque. Là vous vous dites, oui mais il a pris une version 32Go, je vous réponds oui mais l'OS annonce 17Go de libre alors qu'aucune application tierce n'est installée...

Enfin, le côté frustrant dès le déballage du produit est la mise à jour de pas moins de 17 applications. Du coup, il faut soit paramétrer avant de lancer les mises à jour ou bien patienter 2 heures.

Conclusion

Cette Surface est un beau produit qui sait bien mettre en avant les nouvelles fonctionnalités de Windows 8 et on en attendait pas moins de Microsoft. Maintenant, espérons que les fabricants de hardware emboitent leur pas pour l'innovation.

27/10/2012

[XAML] Bubbling, Tunneling et Konami

Allez aujourd'hui on fait un tout petit topo technique sur une particularité XAML à savoir le bubbling et le tunneling et ensuite on va voir une mise en application ludique et amusante.

Alors on commence par le point théorique.
Lorsque que l'on gère les événements en XAML, on va utiliser 3 types différents d'événements routés

Les événements directs, les événements de type bulle (bubbling) et les événements de type tunnel (tunneling).

Donc pour illustrer rapidement ces trois concepts, on part du postulat que vous avec ceci :

<Grid x:Name="myGrid">
  <StackPanel x:Name="myStackPanel">
    <TextBox x:Name="myTextBox"/>          
  </StackPanel>
</Grid>

Evénements directs

Ici rien de nouveau neuf, on est sur ce qu'il a de plus classique comme cela était géré avec les Forms (Win ou Web). En exemple :

<Grid x:Name="myGrid">
  <StackPanel x:Name="myStackPanel">
    <TextBox x:Name="myTextBox" TextChanged="myTextBox_TextChanged"/>          
  </StackPanel>
</Grid>
Ici l'événement levé sera celui de la modification du texte de la TextBox.


Evénements de type bulle (bubbling)

Le Bubbling va nous permettre de lever un événement ou des événements dans un ordre précis. Ici chaque élément graphique s'abonne au même événement.

<Grid x:Name="myGrid" KeyDown="myGrid_KeyDown" >
  <StackPanel x:Name="myStackPanel" KeyDown="myStackPanel_KeyDown">
    <TextBox x:Name="myTextBox" KeyDown="myTextBox_KeyDown"/>          
  </StackPanel>
</Grid>
Ici le premier élément graphique a lever l'événement sera la TextBox puis le StackPanel et enfin la Grid.


Evénements de type tunnel (tunneling)

Le Tunneling va nous permettre la même granularité :

<Grid x:Name="myGrid" PreviewKeyDown="myGrid_PreviewKeyDown" >
  <StackPanel x:Name="myStackPanel" PreviewKeyDown="myStackPanel_PreviewKeyDown">
    <TextBox x:Name="myTextBox" PreviewKeyDown="myTextBox_PreviewKeyDown"/>          
  </StackPanel>
</Grid>
Ici le premier élément graphique a lever l'événement sera la Grid puis le StackPanel et enfin la TextBox.

Conclusion

D'une manière générale, les événements qui nous permettent de gérer le bubbling sont suffixé de "Down" et ceux pour le tunneling sont préfixé de "Preview". Voilà pour le petit topo. Maintenant on s'amuse...

Coding4Fun

Maintenant qu'on sait faire ça, on fait quoi ? Pour une fois je suis parti d'une idée et pas d'une particularité technique. Donc Aujourd'hui, je vous propose de mettre en place dans nos applications .NET, une fonctionnalité totalement old school, totalement geek, totalement inutile donc totalement indispensable, c'est à dire un Konami Code. C'est parti

On commence par créer notre classe qui va gérer le Code Konami.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

namespace KonamiWPF
{
    public class KonamiCode
    {
        
        //La belle séquence Konami
        List Konami = new List
        {
            Key.Up, Key.Up,
            Key.Down, Key.Down,
            Key.Left, Key.Right,
            Key.Left, Key.Right,
            Key.B, Key.A
        };

        //notre index pour analyser la séquence
        public int myIndex { get; set; }

        public bool IsCompletedBy(Key myKey)
        {
            //on vérifie que la nouvelle touche pressé correspondent à la série
            if (Konami[myIndex + 1] == myKey)
            {
                myIndex++;
            }

            //mis en place si 3 Key.Up sont rentrés, il ne réinitialise pas analyse de la séquence
            else if (myIndex == 1 && myKey == Key.Up)
            {

            }
            
            // Démarrage de l'analyse de la séquence
            else if (Konami[0] == myKey)
            {
                myIndex = 0;
            }
            else
            {
                myIndex = -1;
            }
            // Si on arrive au bout on renvoie true et on réinitialise
            if (myIndex == Konami.Count -1)
            {
                myIndex = -1;
                return true;
            }
            return false;
        }
    }
}

Maintenant on reprends la même exemple de code XAML :

<Grid x:Name="myGrid" PreviewKeyUp="myGrid_PreviewKeyUp" >
  <StackPanel x:Name="myStackPanel">
    <TextBox x:Name="myTextBox"/>          
  </StackPanel>
</Grid>

Du coup, on fait un petit traitement juste pour vérifier si le Konami est correctement pris en charge.

public partial class MainWindow : Window
    {
        private KonamiCode seq;
        public MainWindow()
        {
            InitializeComponent();
            seq =  new KonamiCode();
        }

        private void myGrid_PreviewKeyUp(object sender, KeyEventArgs e)
        {
            if (seq.IsCompletedBy(e.Key))
            {
                myTextBox.Text = "Konami !!!";
            }
        }
    }

Maintenant je vous laisse faire preuve d'inventivité pour vos créations graphiques et bon code (Konami bien sûr ^^).

12/02/2012

[XAML] Les Converters

Bon aujourd'hui un petit topo sur les converters en WPF, c'est simple, rapide et ça peut rapporter gros !!
Après une expérience de conversions tout à fait improbable (sur 4 couches applicatives!!!) sur un projet en Debug, il va être bon de rappeller les fondemmentaux :

a - Conversion monétaire


Allez on assume que les prix sont stockés dans notre base en Euros sous un format decimal !
Alors on va créer notre converter :
Using ...

namespace MyConverterApp
{
   [System.Windows.Data.ValueConversion(typeof(decimal), typeof(string))]
   class ConvertMoneyInEuros : System.Windows.Data.IValueConverter
   {
       public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo cultureInfo)
       {
           decimal myPrice = decimal.Parse(value.ToString());
           return myPrice.ToString("C");
       }

       public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo cultureInfo)
       {
           string aMyPrice = value.ToString();
           decimal result;
           if(decimal.TryParse(aMyPrice, System.GLobalization.NumberStyles.Any, null, out result)
           {
              return result;
           }
           else
              return 0;
       }
   }
}

Ensuite on instancie dans le XAML :
<Window x:Class="MyConverterApp"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

 xmlns:local="clr-namespace:MyConverterApp"

        Title="MainWindow" Height="350" Width="525">
<Window.Resources>
   <local:ConvertMoneyInEuros x:Key="DisplayInEuros"/>
</Window.Resources>
 ...
<Window>

Puis il ne nous reste plus qu'à l'utiliser dans notre Elément d'interface (en supposant un DataContext dans la Grid) :
<Grid Name="Grid1">
   <StackPanel>
      <label Content={Binding Path=UnitPrice, Converter={StaticResource DisplayInEuros}}
   </StackPanel>

Et cela nous affiche un joli 12,50 € !

Supposons maintenant que nous souhaitions l'afficher en dollars US mais pas comme font certains, qu'un produit à $6.00 ne devienne pas un produit vendu à 6,00 €... Mais bien que notre "12,50 €" devienne un "$9.52" Alors on créé simplement un nouveau converter :
Using ...

namespace MyConverterApp
{
   [System.Windows.Data.ValueConversion(typeof(decimal), typeof(string))]
   class ConvertMoneyInUSDollars : System.Windows.Data.IValueConverter
   {
      readonly decimal _rate = decimal.Parse("1,3131");
      readonly System.Globalization.CultureInfo _usCulture = new System.Globalization.CultureInfo("en-US");
      readonly System.Globalization.CultureInfo _currentcult = System.Globalization.CultureInfo.CurrentCulture;

      public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo cultureInfo)
      {
         decimal myPrice = decimal.Parse(value.ToString());
         myPrice = myPrice /_rate
         return myPrice.ToString("C", _usCulture);
         
      }

      public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo cultureInfo)
      {
         string aMyPrice = value.ToString();
         decimal result;
         if(decimal.TryParse(aMyPrice, System.GLobalization.NumberStyles.Any, null, out result)
         {
            result = result * _rate;
            return result;
         }
         else
            return 0;
      }
   }
}

Supposons maintenant souhaite basculer dynamiquement dans le code d'un affichage en Euros à un affichage en Dollars US avec un bouton radio par exemple :
        private void RadioButtonEURClick(object sender, RoutedEventArgs e)
        {
            var bd = new Binding();
            bd.Converter = new ConvertMoneyInEuros();
            bd.Path = new PropertyPath("UnitPrice");
            bd.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            bd.Mode = BindingMode.TwoWay;

            MyDynamicTextBox.SetBinding(TextBox.TextProperty, bd);
        }

        private void RadioButtonUSDClick(object sender, RoutedEventArgs e)
        {
            var bd = new Binding();
            bd.Converter = new ConvertMoneyInUsDollars();
            bd.Path = new PropertyPath("UnitPrice");
            bd.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            bd.Mode = BindingMode.TwoWay;

            MyDynamicTextBox.SetBinding(TextBox.TextProperty, bd);
        }

b - Conversion d'image


Les exemples présentés ici sont uniquement pour illustrer à nouveau les principes des converters à vous de les réadapter.
Voilà un converter pour remplacer le chemin d'accès à une image en image :
Using ...

namespace MyConverterApp
{
   [System.Windows.Data.ValueConversion(typeof(string), typeof(BitmapImage))]
   class ConvertStringToBitmap : System.Windows.Data.IValueConverter
   {

      public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo cultureInfo)
      {
         try
         {
            string myPath = (string)value;
            Uri myUri = new Uri(myPath);
            BitmapImage myImage = new BitmapImage(myUri);
            return myImage;
         }
         catch
         {
            return new BitmapImage(new Uri("C:\\ImageNotAvailable.jpg"));
         }
      }
      
      public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo cultureInfo)
      {
         throw new NotImplementedException();
      }
   }
}

Pour résumer, les converters sont un moyens efficaces d'effectuer diverses convertions au niveau de l'IHM.

13/12/2011

[TryAndLikeIt] Un jour, une appli

Grâce à l'opportunité qui m'est offert par le programme Try and like it de Microsoft, je vais vous faire découvrir les applications Nokia qui sont disponible avec le Nokia 800 :

Nokia Musique

09/12/2011

[TryAndLikeIt] Quelques semaines à la découverte du Nokia Lumia 800



La nouvelle est tombée juste avant de partir en week-end : Je viens d'être sélectionné par Microsoft pour promouvoir le Windows Phone 7.5 sur la ville de Toulouse durant les prochaines semaines !

Si tout ce passe comme convenu je devrais aller chercher mon Nokia Lumia 800 la semaine prochaine ! Ca fait vraiment plaisir ! Donc je pense poster très prochainement poster une critique de ce téléphone et faire certainement une comparaison avec le Samsung Omnia 7 que je possède déjà ! :)

Si vous êtes sur le ville de Toulouse et que vous souhaitez une démonstration du Téléphone, n'hésitez pas à me le faire savoir. (Par contre il faut m'en commander 10 pour que je me déplace !!) ^^

Voilà normalement des news très prochainement !

12/10/2011

[XAML] Notifications dans la barre de tâches

En dépannage (qui devient souvent permanent), on a parfois besoin de créer de petits outils avec un accès rapide à 2-3 fonctionnalitées sans forcément nécessiter une (grosse) interface graphique. Moi j'obte dans ce cas pour une application silencieuse avec des accès direct depuis la zone de notification.

Et bien voilà, en WPF rien de natif pour créer des icônes dans la zone de notification et pour celles et ceux qui me lise déjà, vous savez que je ne suis pas fan de réutiliser des Winforms pour pallier à ce problème. J'utilise donc une API qui a été développée par Philipp Sumi. Son API est très efficace pour avoir rapidemment un résultat et en même temps permets d'affiner très précisément si besoin.

On démarre par télécharger le projet ici

On ouvre, on compile, et on va chercher la merveilleuse : Hardcodet.Wpf.TaskbarNotification.dll

Donc notre projet, on rajoute la dll en référence ("Project", "Add Reference...")

Puis on l'instancie dans le XAML :

xmlns:systray="clr-namespace:Hardcodet.Wpf.TaskbarNotification;assembly=Hardcodet.Wpf.TaskbarNotification"

Ensuite on rajoute notre composant :
<systray:TaskbarIcon x:Name="mySystrayIcon" IconSource="/Images/test.ico" ToolTipText="Test">
</systray:TaskbarIcon>

Pour rajouter un menu contextuel, rien de plus simple, celui ci est disponible :
<systray:TaskbarIcon x:Name="mySystrayIcon" IconSource="/Images/test.ico" ToolTipText="Test">
   <systray:TaskbarIcon.ContextMenu>
      <ContextMenu>
         <MenuItem Header="Test"/>
      </ContextMenu>
   </systray:TaskbarIcon.ContextMenu>
</systray:TaskbarIcon>

Ce qui m'a de suite séduit dans cette API c'est le fait de pouvoir utiliser des UserControl pour effectuer ses notifications.

Vous créez donc votre notification dans un Userontrol :


Ensute on rajoute bien évidemment la référence vers le local :
xmlns:local="clr-namespace:MonApplication"

Et on l'intègre de cette façon :
<systray:TaskbarIcon x:Name="mySystrayIcon" IconSource="/Images/test.ico" ToolTipText="Test">
   <systray:TaskbarIcon.TrayPopup>
      <local:MyUserControl/>
   </systray:TaskbarIcon.TrayPopup>
   <systray:TaskbarIcon.ContextMenu>
      <ContextMenu>
         <MenuItem Header="Test"/>
      </ContextMenu>
   </systray:TaskbarIcon.ContextMenu>
</systray:TaskbarIcon>
Ensuite si vous souhaitez utiliser votre User Control à partir du code behind, vous allez procéder comme ceci :

private void ShowMyUserControl()
{
   mySystrayIcon.ShowCustomBalloon(new MyUserControl(), System.Windows.Controls.Primitives.PopupAnimation.Slide, 2500);
}
Personnellement j'aime utiliser mes petites applications de cette manière là c'est à dire avec juste un menu contextuel personnalisé qui s'efface lorsqu'il perd le focus. Ce qui donne :
<systray:TaskbarIcon x:Name="mySystrayIcon" IconSource="/Images/test.ico" ToolTipText="Test" PopupActivation="RightClick" TrayLeftMouseUp="mySystrayIcon_TrayLeftMouseUp" >
   <systray:TaskbarIcon.TrayPopup>
      <local:UC LostFocus="UC_LostFocus"/>
   </systray:TaskbarIcon.TrayPopup>
</systray:TaskbarIcon>
Et dans mon code behind:

public MainWindow()
{
   this.Visibility = System.Windows.Visibility.Hidden;
}

private void UC_LostFocus()
{
   this.Close();
}

private void mySystrayIcon_TrayLeftMouseUp()
{
   //Traitement sur le clic gauche.
}
Vous avez également remarqué que je me suis abonné à TrayLeftMouseUp qui me permet de gérer mon clic gauche.

Vous pouvez retrouver le tutoriel intégral de Philipp Sumi en anglais sur The Code Project, il couvre vraiment la plupart des cas (Du moins les miens ont trouvés toutes les réponses) et notamment approfondie la partie command, routed event, databindig.

02/09/2011

[SL5] Nouveautés de Silverlight 5 - SL5 RC

Voilà la nouvelle version de Silverlight est sortie depuis quelques heures en version RC.
Pour rappel la version Release Candidate n'est pas la version définitive. Je vous conseille d'autant plus de prendre vos précautions, (genre d'installer cette version dans une VM), car certains développeurs de la communauté ont d'ores et déjà remonté des problèmes pour faire fonctionner ensuite correctement leur précédentes applications (Framework antérieur). Le runtime est pourtant sensé supporter toutes les versions... :( A suivre avec la version finale...
Allez c'est parti, on commence par ici, et on mets à jour son Visual Studio (SP1) si cela n'a pas déjà été fait avec le SDK Windows Phone.

Bref donc Prérequis VS2010 SP1.
Puis SL5 Tools for VS2010 SP1, etc... etc...,

Bon alors quelles sont les nouveautés de cette version :

 - Prise en charge des versions X64.
 - Amélioration des performances réseaux.
 - Amélioration du temps de latence du flux audio.
 - Prise en charge du format H264
 - Prise en charge de l'impression vectorielle
 - Amélioration des rendus 3D et de la prise en charge du GPU. Pour plus d'infos sur ce sujet je ne serais trop vous recommander le blog de David Catuhe ici.
 - Full Trusted Application : Accès complet aux fichiers systèmes de la machine depuis notre application Silverlight. (BDR modifié, certificat de l'éditeur accepté dans le navigateur.)

La liste n'est pas complète. Je ne note ici que les innovations qui me sont apparues les plus significatives

Pour plus d'informations : http://go.microsoft.com/fwlink/?LinkId=214343

Maintenant au boulot, y'a plus qu'à s'amuser!

EDIT : Vous pouvez récupérer la documentation complète de cette nouvelle version ICI !