Archive for the 'Composants' Category


DonutLoader [Custom Control]

Aucun commentaire


    Pour les besoins d'une production, nous avons eu besoin d'un visuel d'attente (Torus ou Donut Loader) très proche de ce qui se fait déjà déjà sous Windows. Pour cela, j'ai étendu Control puis j'ai ajouté quelques Dependency properties :

    #region Dps
     
    /// 
    /// Set the speed of animation based on
    /// 
    [Category("Common Properties")]
    [Description("Allow to define animation's duration")]
    public TimeSpan Duration
    {
        get { return (TimeSpan)GetValue(DurationProperty); }
        set { SetValue(DurationProperty, value); }
    }
     
    // Using a DependencyProperty as the backing store for SpeedRatio.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DurationProperty =
        DependencyProperty.Register("Duration", typeof(TimeSpan), typeof(DonutLoader), new PropertyMetadata(TimeSpan.FromSeconds(1), new PropertyChangedCallback(OnDurationChanged)));
     
    private static void OnDurationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var donutLoader = d as DonutLoader;
     
        if (d != null)
        {
            ClockState cs = donutLoader.boucle.GetCurrentState()
     
            donutLoader.boucle.Stop();
     
            donutLoader.daBoucle.Duration = (TimeSpan)e.NewValue;
     
            if (cs == ClockState.Active)
            {
                donutLoader.boucle.Begin();
            }
        }
    }
     
    /// 
    /// Percent of progression
    /// 
    [Category("Common Properties")]
    [Description("Current progression value")]
    public double Percent
    {
        get { return (double)GetValue(PercentProperty); }
        set { SetValue(PercentProperty, value); }
    }
     
    // Using a DependencyProperty as the backing store for Percent.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty PercentProperty =
        DependencyProperty.Register("Percent", typeof(double), typeof(DonutLoader), new PropertyMetadata(0d));
     
    /// 
    /// Allow to  hide percent textBlock
    /// 
    [Category("Common Properties")]
    [Description("Show/Hide progression value")]
    public Visibility PercentVisibility
    {
        get { return (Visibility)GetValue(PercentVisibilityProperty); }
        set { SetValue(PercentVisibilityProperty, value); }
    }
     
    // Using a DependencyProperty as the backing store for PercentVisibility.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty PercentVisibilityProperty =
        DependencyProperty.Register("PercentVisibility", typeof(Visibility), typeof(DonutLoader), new PropertyMetadata(Visibility.Visible));
     
    #endregion

    A ce stade, tout fonctionne comme prévu, mais un petit bug m'a pris un peu de temps à résoudre dans les lignes suivantes.

    private void SetOpacityMask()
    {
    BitmapImage bi = new BitmapImage() { UriSource = new Uri("/Tweened.Controls;component/bitmaps/ProgressBitmap.png", UriKind.RelativeOrAbsolute) };
     
         ImageBrush ib = new ImageBrush();
     
         ib.ImageSource = bi;
     
         _DonutFrameworkElement.RenderTransform = new CompositeTransform() { CenterX = .5, CenterY = .5 };
     
         _DonutFrameworkElement.OpacityMask = ib;
    }
     
    private void SetStoryboard()
    {
         boucle.Children.Add(daBoucle);
     
         Storyboard.SetTargetProperty(daBoucle, new PropertyPath("(UIElement.RenderTransform).(CompositeTransform.Rotation)"));
     
         daBoucle.From = 0;
     
         daBoucle.To = -360;
     
         daBoucle.RepeatBehavior = RepeatBehavior.Forever;
     
         daBoucle.Duration = Duration;
    }

    Lorsque l'on joue l'animation de rotation par C# ou XAML, l'objet qui subit l'animation disparaît soudainement au runtime. Après avoir passé un peu de temps sur ce bug, j'ai décidé non pas d'animer l'objet lui même mais son remplissage :

    private void SetOpacityMask()
    {
        BitmapImage bi = new BitmapImage() { UriSource = new Uri("/Tweened.Controls;component/bitmaps/ProgressBitmap.png", UriKind.RelativeOrAbsolute) };
     
        ImageBrush ib = new ImageBrush();
     
        ib.ImageSource = bi;
     
        ib.RelativeTransform = new CompositeTransform() { CenterX = .5, CenterY = .5 };
     
        //ancienne version
        //_DonutFrameworkElement.RenderTransform = new CompositeTransform() { CenterX = .5, CenterY = .5 };
     
        _DonutFrameworkElement.OpacityMask = ib;
    }
     
    private void SetStoryboard()
    {
        boucle.Children.Add(daBoucle);
     
        Storyboard.SetTargetProperty(daBoucle, new PropertyPath("(UIElement.OpacityMask).(Brush.RelativeTransform).(CompositeTransform.Rotation)"));
     
        //ancienne version
        //Storyboard.SetTargetProperty(daBoucle, new PropertyPath("(UIElement.RenderTransform).(CompositeTransform.Rotation)"));
     
        daBoucle.From = 0;
     
        daBoucle.To = -360;
     
        daBoucle.RepeatBehavior = RepeatBehavior.Forever;
     
        daBoucle.Duration = Duration;
    }

    j'ai donc remplacé la ligne ciblant la propriété à animer :

    Storyboard.SetTargetProperty(daBoucle, new PropertyPath("(UIElement.RenderTransform).(CompositeTransform.Rotation)"));

    par :

    Storyboard.SetTargetProperty(daBoucle, new PropertyPath("(UIElement.OpacityMask).(Brush.RelativeTransform).(CompositeTransform.Rotation)"));

    Là, au miracle, plus aucun bug, tout fonctionne parfaitement. C'est la première fois que j'anime, au sein d'un custom contrôle, un objet avec une image en masque d'opacité et j'ai bien perdu 30 minutes là dessus. Si quelqu'un a une idée du pourquoi de ce bug je suis preneur.

    RadioButton Extension [Custom Control] [API]

    Aucun commentaire


      Pour les nécessités d'un projet, j'ai récemment eu besoin de conserver l'historique des sélections effectuées au sein d'un groupe de RadioButton. Cette classe existe sur des environnements comme Flex de manière native mais pas sur Silverlight, du coup, il est nécessaire de concevoir un mini framework pour avoir le même type de fonctionnalités. Généralement la classe RadioButtonGroup possède un événement Selected diffusé lorsqu'un des RadioButton est sélectionné au sein du groupe. Toutefois pour les besoins de la production, nous avions besoin d'historier les sélections successives car ceux-ci était utilisés comme menu. Du coup, j'ai développé une mini API permettant de faire cela et un peu plus.

      Cette API est composée de différents éléments :
      - La classe RadioButtonGroup
      - Des propriétés attachées pour activer / désactiver / stocker un groupe de radio boutton associé.
      - Une méthode d'extension
      - Un comportement facilitant l'activation de RadioButtonGroup (à glisser dans Blend sur un RadioButton)

      Il est intéressant de constater qu'utiliser un comportement peut s'avérer bien plus souple qu'utiliser une Attached Property. Bien qu'une Attached Property puisse être définit dans un style, celle-ci le constructeur d'une MainPage ne pourra pas accéder à une instance de RadioButtonGroup directement. Vous pourrez le faire uniquement sur le Loaded. Dans le cas du comportement cela n'est pas vrai car le RadioButtonGroup est instancié via la méthode OnAttached qui est appelée dès que le comportement est affecté à un RadioButton, c'est à dire bien avant son affichage effectif. Je mets un projet de test au téléchargement ici.

      Pour chacun d'eux, je mets le code en clair dans les sections ci-dessous :

      La classe RadioButtonGroup

      Celle-ci possède plusieurs membres très utiles :

      • SelectionChanged

      Cet événement est diffusé lorsqu'un RadioButton du groupe est sélectionné.

      • Children

      CollectionObservable contenant tous les RadioButton du groupe

      • Historic

      CollectionObservable contenant l'historique de sélection

      • Current

      Propriété renvoyant le RadioButton actuellement sélectionné

      • Last

      Propriété renvoyant le RadioButton précédemment sélectionné

      • Add

      Méthode permettant d'ajouter un RadioButton au groupe

      • Remove

      Méthode permettant de supprimer un RadioButton du groupe

      • CancelLastSelection

      Annule la dernière sélection. Très pratique pour certaines fonctionnalités spécifiques aux menus

      public class RadioButtonGroup : INotifyPropertyChanged
      {
       
          ///
          /// This event is fired when the selected RadioButton has been modified.
          ///
          public event EventHandler
       SelectionChanged;
       
          private bool _IsCanceledByGroup;
          public bool IsCanceledByGroup
          {
              get
              {
                  return _IsCanceledByGroup;
              }
              set
              {
                  _IsCanceledByGroup = value;
              }
          }
       
          ///
          /// ObservableCollection wich contains an historic of selected RadioButton
          ///
          private ObservableCollection _Historic = new ObservableCollection();
          public ObservableCollection Historic
          {
              get
              {
                  return _Historic;
              }
              set
              {
                  _Historic = value;
              }
          }
       
          ///
          /// ObservableCollection of RadioButton contained by the RadioButtonGroup
          ///
          private ObservableCollection _Children = new ObservableCollection();
          public ObservableCollection Children
          {
              get
              {
                  return _Children;
              }
              set
              {
                  _Children = value;
              }
          }
       
          ///
          /// Returns Current Selected RadioButton in the group
          ///
          private RadioButton _Current;
          public RadioButton Current
          {
              get
              {
                  return _Current;
              }
              set
              {
                  if (!Object.ReferenceEquals(_Current, value))
                  {
                      _Current = value;
       
                      NotifyPropertyChanged("Current");
       
                      if (SelectionChanged != null)
                      {
                          SelectionChanged(this, new SelectedChangedEventArgs() { Last=_Last,Current=_Current, CurrentGroup=this });
                      }
       
                  }
              }
          }
       
          ///
          /// Returns last selected RadioButton in the group
          ///
          private RadioButton _Last;
          public RadioButton Last
          {
              get
              {
                  return _Last;
              }
              set
              {
                  if (!Object.ReferenceEquals(_Current, value))
                  {
                      _Last = value;
       
                      NotifyPropertyChanged("Last");
                  }
              }
          }
       
          ///
          /// Add a RadioButton to the RadioButtonGroup
          ///
          ///
       
          public void Add(RadioButton rb)
          {
              _Children.Add(rb);
              rb.Checked += new RoutedEventHandler(rb_Checked);
          }
       
          ///
          /// Remove a RadioButton contained by the RadioButtonGroup
          ///
          ///
       
          public void Remove(RadioButton rb)
          {
              _Children.Remove(rb);
              rb.Checked -= new RoutedEventHandler(rb_Checked);
          }
       
          ///
          /// Cancel last selection in the group and select the one before
          ///
          /// Return Current Selection after CancelLastSelection method has been called.
          public void CancelLastSelection()
          {
       
              if (Historic.Count > 1)
              {
                  Historic.RemoveAt(Historic.Count - 1);
              }
              Historic[Historic.Count - 1].IsChecked = true;
          }
       
          private void rb_Checked(object sender, RoutedEventArgs e)
          {
              Current = sender as RadioButton;
       
              Historic.Add(Current);
       
              Last = Historic[Historic.Count - 1];
          }
       
          #region NPC members
       
          public event PropertyChangedEventHandler PropertyChanged;
       
          private void NotifyPropertyChanged(string prop)
          {
              if (PropertyChanged != null)
              {
                  PropertyChangedEventArgs e = new PropertyChangedEventArgs(prop);
                  PropertyChanged(this, e);
              }
          }
       
          #endregion
       
      }

      Des propriétés de dépendance attachées (aux RadioButton) facilitant l'activation et l'instanciation d'un objet RadioButtonGroup.

      ActivateRadioButtonGroup permet d'activer la gestion via RadioButtonGroup.
      CommitProperty permet de sélectionné un RadioButton lorsqu'une propriété de votre choix est modifiée.

      namespace Tweened.Extensions.RadioButtonEx
      {
       
          public static partial class RadioButtonExtension
          {
              #region static Dictionnary string / RadioButtonGroup named RadioButtonGroups
              private static Dictionary _RadioButtonGroups = new Dictionary();
              ///
              /// Contains RadioButtonGroups in the application
              ///
              public static Dictionary RadioButtonGroups
              {
                  get
                  {
                      return _RadioButtonGroups;
                  }
                  set
                  {
                      _RadioButtonGroups = value;
                  }
              }
              #endregion
       
              #region Commit DependencyProperty enables the radiobutton to autoselect if some property has changed
              ///
              /// Enable the radiobutton to autoselect if some property has changed
              ///
              public static object GetCommitProperty(DependencyObject obj)
              {
                  return (object)obj.GetValue(CommitPropertyProperty);
              }
       
              public static void SetCommitProperty(DependencyObject obj, object value)
              {
                  obj.SetValue(CommitPropertyProperty, value);
              }
       
              // Using a DependencyProperty as the backing store for CommitProperty.  This enables animation, styling, binding, etc...
              public static readonly DependencyProperty CommitPropertyProperty =
                  DependencyProperty.RegisterAttached("CommitProperty", typeof(object), typeof(RadioButton), new PropertyMetadata(null,
                                                                                                              new PropertyChangedCallback(OnCommitProperty)));
       
              private static void OnCommitProperty(DependencyObject d, DependencyPropertyChangedEventArgs e)
              {
                  RadioButton rb = d as RadioButton;
                  if (rb == null)
                  {
                      return;
                  }
       
                  if (e.NewValue != e.OldValue)
                  {
       
                      rb.IsChecked = e.NewValue != null;
                  }
              }
              #endregion
       
              #region ActivateRadioButtonGroup DependencyProperty enables RadioButtonGroup management for a given RadioButton
       
              ///
              /// Retrieves the RadioButtonGroup wich hold the RadioButton.
              ///
              ///
       
              ///
              public static RadioButtonGroup GetRadioButtonGroup(DependencyObject obj)
              {
                  return (RadioButtonGroup)obj.GetValue(RadioButtonGroupProperty);
              }
       
              public static void SetRadioButtonGroup(DependencyObject obj, RadioButtonGroup value)
              {
                  obj.SetValue(RadioButtonGroupProperty, value);
              }
       
              // Using a DependencyProperty as the backing store for RadioButtonGroup.  This enables animation, styling, binding, etc...
              private static readonly DependencyProperty RadioButtonGroupProperty =
                  DependencyProperty.RegisterAttached("RadioButtonGroup", typeof(RadioButtonGroup), typeof(RadioButton), null);
       
              ///
              /// Activate RadioButton Group managment
              ///
              ///
       
              ///
              public static bool GetActivateRadioButtonGroup(DependencyObject obj)
              {
                  return (bool)obj.GetValue(ActivateRadioButtonGroupProperty);
              }
       
              public static void SetActivateRadioButtonGroup(DependencyObject obj, bool value)
              {
                  obj.SetValue(ActivateRadioButtonGroupProperty, value);
              }
       
              // Using a DependencyProperty as the backing store for ActivateRadioButtonGroup.  This enables animation, styling, binding, etc...
              public static readonly DependencyProperty ActivateRadioButtonGroupProperty =
                  DependencyProperty.RegisterAttached("ActivateRadioButtonGroup", typeof(bool), typeof(RadioButton), new PropertyMetadata(false, new PropertyChangedCallback(OnActivateRadioButtonGroupChanged)));
       
              private static void OnActivateRadioButtonGroupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
              {
                  RadioButton rb = d as RadioButton;
       
                  if (rb == null || String.IsNullOrEmpty(rb.GroupName))
                  {
                      throw new Exception("Object is not a RadioButton or GroupName is not defined.");
                  }
       
                  RadioButtonGroup rbg;
       
                  if (System.Convert.ToBoolean(e.NewValue))
                  {
                      if (!RadioButtonExtension.RadioButtonGroups.ContainsKey(rb.GroupName))
                      {
                          rbg = new RadioButtonGroup();
                          RadioButtonExtension.RadioButtonGroups.Add(rb.GroupName, rbg);
                          Application.Current.Resources.Add(rb.GroupName, rbg);
                          rbg.Add(rb);
                      }
                      else
                      {
                          rbg = RadioButtonExtension.RadioButtonGroups[rb.GroupName];
                          rbg.Add(rb);
                      }
                      RadioButtonExtension.SetRadioButtonGroup(rb, rbg);
                  }
                  else
                  {
                      if (RadioButtonExtension.RadioButtonGroups.ContainsKey(rb.GroupName))
                      {
                          rbg = RadioButtonExtension.RadioButtonGroups[rb.GroupName];
                          rbg.Remove(rb);
                          RadioButtonExtension.SetRadioButtonGroup(rb, null);
                      }
                  }
       
              }
       
              #endregion
          }
      }

      Des comportements que vous pourrez glisser directement sur des instances de RadioButton ou un conteneur en contenant.

      public class RadioButtonGroupBehavior : Behavior
      {
      	public RadioButtonGroupBehavior()
      	{
       
      	}
       
      	protected override void OnAttached()
      	{
      		base.OnAttached();
       
              	if (AssociatedObject is Panel)
              	{
                  		AssociatedObject.Loaded += new RoutedEventHandler(AssociatedObject_Loaded);
              	}
             		else if (AssociatedObject is RadioButton)
              	{
                 		RadioButtonExtension.SetActivateRadioButtonGroup(AssociatedObject as RadioButton, true);
              	}
      	}
       
      	void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
      	{
      		foreach (UIElement b in (sender as Panel).Children)
      		{
      			if (b as RadioButton != null)
      				RadioButtonExtension.SetActivateRadioButtonGroup(b as RadioButton, true);
      		}
      	}
       
      	protected override void OnDetaching()
      	{
      		base.OnDetaching();
       
              	if (AssociatedObject is Panel)
              	{
                  		AssociatedObject.Loaded -= AssociatedObject_Loaded; 
       
                  		foreach (RadioButton b in (AssociatedObject as Panel).Children)
                  		{
                      		RadioButtonExtension.SetActivateRadioButtonGroup(b, false);
                  		}
              	}
              	else if (AssociatedObject is RadioButton)
              	{
                 		 RadioButtonExtension.SetActivateRadioButtonGroup(AssociatedObject as RadioButton, false);
              	}
      	}
       
      }

      Une méthode d'extension pour les instances de RadioButton qui facilite la récupération du RadioButtonGroup associé.

      public static partial class RadioButtonExtension
      {
          #region Extension Method GetRadioButtonGroup
          ///
          /// Allow to get the RadioButtonGroup associated to a RadioButton
          ///
          ///
       
          ///
          public static RadioButtonGroup GetRadioButtonGroup(this RadioButton radioButton)
          {
              RadioButtonGroup rbg = null;
       
              if (RadioButtonExtension.RadioButtonGroups.ContainsKey(radioButton.GroupName))
              {
                  rbg = RadioButtonExtension.RadioButtonGroups[radioButton.GroupName];
              }
       
              return rbg;
          }
          #endregion
      }

      UniformGrid for Silverlight [Custom Control]

      Aucun commentaire

        Je n'ai jamais compris pourquoi le conteneur d'agencement UniformGrid n'était pas dans le silverlight ToolKit. Contrairement à ce que l'on peut imaginer, il n'est pas toujours remplaçable par un WrapPanel. J'ai donc porté l'existant WPF vers Silverlight. Comme ce panneau est relativement utile, voici la classe UniformGrid en téléchargement.

        Silverlight Bing Map for Wordpress [Plugin]

        1 commentaire

          Get Microsoft Silverlight

          Voici un nouveau plugin pour wordpress. L'idée est cette fois de faciliter l'intégration d'une carte interactive basée sur Silverlight Bingmap. Pour cela rien de plus simple, il suffit d'installer le plugin que vous trouverez en téléchargement ici.

          Get Microsoft Silverlight

          Silverlight Smooth Streaming for WordPress [Plugin]

          10 commentaires
          Get Microsoft Silverlight

          Je mets en ligne un nouveau plugin wordpress. Il s'agit d'un lecteur vidéo smooth streaming également capable de lire une vidéo standard au format wmv, ou mov, mp4 (lorsque la vidéo est encodée en H264). Il vous faudra tout de même héberger la vidéo sur un serveur IIS si vous souhaitez bénéficier du smooth streaming. Le configurer est relativement simple puisque nous fournissons une fenêtre d'administration côté WordPress. Celle-ci possède un aperçu du lecteur, la possibilité de modifier la couleur, l'url de la vidéo, la lecture automatique, les dimensions ainsi que la couleur de fond du player. Celui-ci vous avertit, lorsque la vidéo n'est pas hébergée sur votre serveur, des contrainte de sécurité que vous pourriez rencontrer (crossdomain.xml ou clientaccesspolicy.xml nécessaire et configuré).

          J'ai réalisé la conception côté Silverlight mais je n'ai pas utilisé pour cela le player fourni par Microsoft. J'ai préféré utiliser la librairie SLExtensions conçues par la société Ucaya spécialisée dans la conception de ce type de lecteur. Par le passé, Ucaya a réalisé les players du "Tour de France", "Rolland Garros", "France Télévision" et j'en passe. Quels sont les avantages me direz-vous ? C'est tout simple. Tout d'abord les fonctionnalités apportée par la librairie sont ultra complètes. De plus, celle-ci offre la possibilité de faire du Full MVVM, Du coup l'interface est entièrement Designable (bien mieux que skinnable). Pour finir, sa conception est assez fine car elle permet d'instancier un MediaElement ou l'équivalent pour le smooth streaming selon le type d'url que vous fournissez : ism et isml pour le smooth streaming et wmv, mov, mp4 (H264) pour les vidéos standards. Il est donc possible de faire un player à la carte et d'éviter l'arsenal fourni par la librairie SMF de Microsoft.

          Si vous souhaitez faire la différence entre les différents modes de diffusion existant, vous pouvez consulter les schémas ci-dessous.

          Get Microsoft Silverlight

          Ceux-ci sont directement issus de mon livre Pratique de Silverlight aux éditions Pearson. Vous pouvez consulter de nombreux schémas présent dans le livre sur le blog dédié.

          Yet another Lite 3D Engine to release

          Aucun commentaire

          Je mettrai en ligne courant de l'été une première release de la librairie Tweened. Celle-ci contient notamment, des composants, des behaviors, un wrapper de tween (facilitant la conception d'animation par code) ainsi qu'un mini moteur 3D très simple d'utilisation. En voici un exemple concret téléchargeable ici :

          Install Microsoft Silverlight

          J'ai fais ce moteur avant tout pour des besoins personnels et afin de me remémorer les mathématiques projectives. Réinventer la poudre ne fais quelques fois pas de mal. L'idée est surtout de fournir une dll de moins de 40ko qui permet de faire de la 3D. Celle-ci sera utilisable pour les designers à travers Blend ou dans Visual Studio via C#. Elle concentrera très vite toutes les fonctionnalités de base réellement utiles et que nous n'avons pas actuellement via Blend : Caméra 3D, Container 3D, Scène 3D, détection des normales et z sorting intelligent (plus malin et performant que celui actuellement proposé dans Blend). J'y ajoute une classe utilitaire facilitant l'utilisation de mathématiques projectives.

          Voilà ces composants :

          1. Un conteneur de type Scene3D (hérite de Panel).
            Tous les objets placés en sont sein voient leur propriétés Projection native lockée. Ceux-ci peuvent utilisées les propriétés attachées suivantes :

            • Scene3D.LocalOffsetX
            • Scene3D.LocalOffsetY
            • Scene3D.LocalOffsetZ
            • Scene3D.GlobalOffsetX
            • Scene3D.GlobalOffsetY
            • Scene3D.GlobalOffsetZ
            • Scene3D.RotationX
            • Scene3D.RotationY
            • Scene3D.RotationZ

            Ils sont associés à une instance de type Element3D. Celle-ci est récupérable (lorsque l'événement StartUp de la scène 3d est diffusé) via une méthode d'extension ajoutées pour les instances d'UIElement (GetElement3D).

          2. Une caméra associée au conteneur Scene3D. Celle-ci offre les propriétés suivantes :
            • FieldOfView
            • Plan de clipping proche : NearPlane
            • Plan de clipping éloigné : FarPlane
            • Point de fuite (XVanishingPoint, YVanishingPoint)
            • Déplacement (OffsetXCamera, OffsetYCamera, OffsetZCamera)
            • Rotation (RotateXCamera, RotateYCamera, RotateZCamera)

          Détection du changement de direction de la normale (Backface culling) et du produit scalaire via les événements NormalDirectionChanged et DotProductChanged. Ces événements sont diffusés par les instances de type Element3D.

          Je suis en cours de finition d'un algorithme de tri des profondeurs. Ce moteur devrait être assez optimisé car son rendu ne repose pas sur un DispatcherTimer. Deplus, le pipeline de rendu est assez optimisé car il n'est pas récursif par défaut. Lorsqu'un seul objet est modifié, ce dernier invoque en interne une méthode RenderElement. A contrario, lorsque la scène ou la caméra sont modifiées, il devient récursif et met à jour l'ensemble des objets de la scène... A bientôt donc pour la release finale de la librairie Tweened...

          Galerie WordPress en Silverlight [plugin]

          2 commentaires

          J'ai récemment participé au développement d'un plugin pour wordpress au côté de Boris Forconi. Celui-ci est basé en partie sur celui de Tim Heuer. L'idée était de créer une galerie Silverlight en utilisant l'API wordpress mais en développant la galerie elle-même en Silverlight. Boris s'est occupé de toute la partie PHP et de l'intégration à Wordpress. Pour ma part, j'ai développé la partie Silverlight. L'objectif est de fournir un moyen simple de mettre des images en ligne pour Wordpress comme montré ci-dessous :

          Get Microsoft Silverlight

          Il suffit d'écrire une balise de type : [sl-gallery: ...]

          Vous pouvez définir les paramètres comme indiqué dans l'exemple ci-dessous :

          • width=400
            //définit la largeur de la galerie à 400 pixels
          • height=400
            //définit la hauteur de la galerie à 400 pixels
          • leftArrow=true
            //affiche ou cache la flèche de gauche
          • rightArrow=true
            //affiche ou cache la flèche de droite
          • pageNumbers=true
            //affiche ou cache la pagination
          • thumbnails=true
            //affiche ou cache les vignettes
          • fill=uniform
            //permet d'indiquer un mode de remplissage vous avez le choix entre :
            // uniform (remplissage homothétique partiel selon possibilité)
            // uniformtofill (remplissage avec homothétie)
            // fill(remplissage avec déformation les dimensions)
            // none (préserve les dimensions originales)
          • bgcolor
            //couleur d'arrière plan
          • bgmode
            //sans arrière plan ou avec arrière plan windowless

          La première bonne nouvelle, c'est qu'il est possible d'utiliser un menu pour paramétrer tout ça en 2 secondes. Il s'ajoute à l'administration des articles Wordpress. Une petite fenêtre apparaît lorsque vous cliquez sur le bouton (voir ci-dessous).


          La seconde bonne nouvelle, c'est que nous mettrons rapidement les sources à disposition sur wordpress.com. De cette manière vous pourrez modifier entièrement le visuel de la galerie côté Silverlight. Dans tous les cas, celle-ci récupère dynamiquement les images de la galerie Wordpress. Vous pouvez en télécharger une première version ici.

          Free ColorPicker and ColorChooser [Custom Control]

          13 commentaires

          Je mets en ligne deux nouveaux composants exposés ci-dessous :

          Install Microsoft Silverlight


          Vous pouvez télécharger la librairie tweenedcontrols ici.

          ColorChooser
          Depuis sa version beta, ce contrôle a été largement améliorée. Il est désormais possible de cliquer directement sur la surface des deux nuanciers pour sélectionner une couleur. La propriété SelectedColor est cette fois de type Color. Tous les tests d'écriture d'une couleur sont directement accomplis par cette classe. Cela simplifie beaucoup le code et évite l'utilisation d'une classe de conversion.

          ColorPicker
          Ce composant a pour but de faire apparaitre un ColorChooser via l'utilisation interne d'une instance de Popup. Toute la problématique consiste à placer le ColorChooser à côté du ColorPicker. À cette fin, j'ai créé une méthode d'extension pour la classe Popup. Il est également possible d'accéder au style et template du ColorChooser directement par l'intermédiaire des menus Edit Template=> Edit Aditional Template comme montré ci-dessous.


          ColorPicker possède la propriété de dépendance IsOpen couplée aux événements Opened et Closed.
          Mis à part cette astuce ce contrôle se contente d'exposer, les propriétés et événements du ColorChooser.

          PieProgressBar [Custom Control]

          Aucun commentaire

          Pour les besoins d'une production récente, j'ai du concevoir un contrôle de progression circulaire nommé PieProgressBar. Ce dernier hérite de la classe RangeBase et bénéficie à ce titre de toutes les capacités inhérentes à ce type de contrôle. Il se comporte au final comme n'importe quel contrôle de type ProgressBar avec quelques petites choses en plus. La petite difficulté fut de créer dynamiquement le camembert de progression via C#. Contrairement à WPF, Silverlight ne permet pas de surcharger de méthode permettant de créer de nouveaux genres de Shape. Autrement dit, même si Shape est une classe abstraite, il ne sert à rien d'en hériter car la méthode de conception du tracé ne peut être surchargée.
          L'autre technique consiste à utiliser le "Path mini language" qui permet de créer des figures géométriques en XAML. J'ai du utiliser 3 segments dont un ArcSegment afin de réaliser ce contrôle. comme je ne pouvais pas créer de primitive Pie pour le graphiste sous Blend, il a fallu ruser... La technique consiste a créer dynamiquement le camembert lors de l'assignation d'une partie de contrôle (ControlPart). En interne, les propriétés de remplissage du tracé généré, sont liées aux propriétés du contrôle via une simple liaison de données créées cote C#.
          Vous pouvez en voir des exemplaires ci-dessous et télécharger la librairie tweenedcontrols ici.

          Install Microsoft Silverlight

          Une fois la dll référencée, vous pouvez instancier des contrôle PieProgressBar dans Blend via le panneau Assets comme montré ci-dessous :

          Ce composant va être sans doute inclu comme d'autres dans le projet CodePlex SLExtensions que Thierry Bouquain met à jour en ce moment et que je salue au passage :)

          ColorChooser and ColorPicker prerelease [Custom Control]

          Aucun commentaire

          J'ai récemment eu besoin de contrôles personnalisables de type ColorPicker et ColorChooser, n'en trouvant pas, je les ai conçu from scratch, voici une démo.

          Install Microsoft Silverlight

          Ceux-ci sont en version bêta mais je pense fournir une version finale d'ici le 15 novembre. En attendant, si vous souhaitez tester ces contrôles et télécharger la dll pour test dans SL3, c'est ici.

          Ps : le plugin Silverlight pour WordPress fourni par Tim Heuer est vraiment performant et très utile, merci à lui, je n'utiliserai plus que cette solution :)

          « Previous PageNext Page »