# Monday, June 08, 2009

France Télévisions – L’info en vidéo

Et une nouvelle version pour l’application L’info en vidéo.

Maintenant vous avez accès aux Directs !

ftvi-2 

Une nouvelle entrée “Evenements” dans le menu donne accès à tous les directs. Et lorsqu’une catégorie du menu contient un direct, un picto rouge vous l’indique.

ftvi-3

#    Comments [2] |
# Monday, May 11, 2009

Being the Big Boss

image

En ce début de semaine www.beingthebigboss.com depasse les 14 000 inscrits !!

Venez nombreux prendre les commandes d’une multinationale !

Et n’oubliez pas si vous êtes étudiant le concours www.bigbosstrophy.com se prépare. Inscrivez-vous !

#    Comments [0] |
# Tuesday, April 28, 2009

France Télévisions – L’info en vidéo

Encore une nouvelle version pour l’application L’info en vidéo.

L’accès aux journaux des régions simplifié par l’affichage de celles-ci sur une carte de France :-)

image

Et un accès direct aux différents journaux de chaque région :

image

#    Comments [0] |
# Friday, April 24, 2009

Gestion de la mémoire sous Silverlight / .Net

On m’a interrogé récemment sur la libération de la mémoire des objets en silverlight. Je vais essayer de synthétiser ici ce que j’ai répondu.

Silverlight réagi exactement de la même manière que le framework .Net. La mémoire est gérée par un garbage collector (ramasse-miettes) qui libère les allocations mémoires des objets une fois qu’ils ne sont plus référencés. 

L’application de test

Voila le principe de mon application de test. Au clic sur un bouton, mon application ajoute un usercontrol dans l’arbre visuel et au clic sur un autre bouton, je l’enlève. La seule référence vers mon contrôle est faite par l’arbre graphique. Dans le constructeur de mon usercontrol, j’incrémente un compteur qui m’indique le nombre d’instances en cours et dans le destructeur je le décrémente. Ce compteur est affiché par binding dans l’interface graphique.

Petite parenthèse pour le fonctionnement de l’application, la destruction des objets ne se passe pas dans le thread graphique, pour que la mise a jour du binding fonctionne, je lève l’événement PropertyChanged de AppController par le SynchronizationContext récupéré du thread graphique.

Contrôle sans références

image

A l’ajout de mon usercontrol, on note bien l’incrémentation du compteur.

image

Je clic sur le bouton Remove et je vois que mon compteur est toujours à 1. Le garbage collector ne passe pas tout de suite. Il y a un algorithme qui détermine quand le garbage collector doit passer sur les objets. Pour le besoin de mon application, je vais forcer l’appel au garbage collector au clic sur le bouton Force GC. Il faut noter que c’est une mauvaise pratique que de vouloir appeler soit même de garbage collector. GC.Collect() ne doit être appelée que si vous en avez réellement l’utilité. Un appel trop fréquent peut dégrader les performances de votre application.

image

Le clic sur Force GC ramène bien le compte de référence à 0.

Contrôle s’abonnant à un événement

Comme je vous le précisait dans le fonctionnement de mon application, je ne maintient aucune référence vers mes usercontrol, je n’ai théoriquement rien qui va empêcher le garbage collector de passer. Cependant le contrôle lui même peut faire qu’il ne sera pas libéré. Ici ma classe AppController fourni un événement auquel mes contrôles peuvent s’abonner. MyControl2 va s’abonner à cet événement. Au clic sur le bouton Raise Test event, vous verez que la couleur du usercontrol change.

image

Si vous ajoutez le usercontrol MyControl2, que vous l’enlevez et que vous forcez le garbage collector, vous verrez que l’instance ne se libère pas. Que se passe-t-il ?
Lorsque le contrôle s’est abonné à l’événement de AppController, il a créé un EventHandler (une référence vers une fonction) et l’a ajouté à la liste des fonctions à appeler lorsque l’événement est levé. Un événement n’est rien d’autre qu’une liste de références qui pointe vers les fonctions à appeler. Pour que notre contrôle se libère, il faut donc supprimer cette référence. Un clic sur Clear Test event list demande à AppController de vider sa liste d’événement, un clic sur Force GC remettra les compteurs à 0.

IDisposable

Une bonne pratique pour gérer la libération de ressources internes et le désabonnement d’évenement est d’implémenter l’interface IDisposable. Cette interface vous demande d’implémenter la fonction Dispose dans laquelle vous pouvez remettre à null les références externes, vous désabonnez d’événements, etc…
Le usercontrol MyControl3 implémente cette interface. Lorsque le bouton Remove First Item est cliqué, mon application vérifie si le contrôle à enlever implémente IDisposable et l’appel le cas échéant.

image

Les clics successifs sur Add MyControl3, Remove First Item et Force GC incrémentent et décrémentent bien notre compteur de références.

WeakReference et proxy d’événement

Si vous ne maitrisez pas la logique d’ajout suppression des contrôles, vous ne pouvez pas toujours appeler la IDisposable.Dispose. (A noter que ce n’est pas parce qu’un contrôle n’est plus dans l’arbre d’affichage qu’il faut nécessairement le disposer. Un tabcontrol ajoute et enlève chaque tab de l’abre graphique.)

La classe WeakReference permet de maintenir une référence “qui ne compte pas” du point de vue du garbage collector. La propriété Target de la WeakReference vaut null quand le garbage collector est passé et renvoi l’instance de l’objet sinon.

Ici pour gérer notre abonnement à l’événement, nous allons utiliser ces WeakReference pour pouvoir quand même être libéré. La fonction à appeler en retour de l’événement est : MyControl4.Instance_TestEvent. Cette fonction est privée. WeakListener est une classe interne à MyControl4 et va donc pouvoir appeler cette fonction privée. C’est WeakListener.Instance_TestEvent que nous allons abonner à l’événement de AppController. Lors de l’appel de l’événement, elle va vérifier que sa WeakReference vers MyControl4 est toujours valide, si tel est le cas, cette fonction va transmettre l’appel vers la fonction MyControl4.Instance_TestEvent, sinon elle se désabonne de l’appelant et pourra donc aussi être collecté par le garbage collector.

    public partial class MyControl4 : UserControl

    {

 

        private class WeakListener

        {

            public WeakListener(MyControl4 target)

            {

                weakReference = new WeakReference(target);

            }

 

            private readonly WeakReference weakReference;

 

            public void Instance_TestEvent(object sender, EventArgs e)

            {

                MyControl4 ctrl = (MyControl4)weakReference.Target;

 

                if (ctrl != null)

                {

                    ctrl.Instance_TestEvent(sender, e);

                }

                else

                {

                    ((AppController)sender).TestEvent -= this.Instance_TestEvent;

                }

            }

        }

 

        void Instance_TestEvent(object sender, EventArgs e)

        {

            this.LayoutRoot.Background = new SolidColorBrush(GetRandomColor());

        }

 

       

    }

image

Un clic sur Add MyControl4, Remove et Force GC vous donnera un compte de référence de MyControl4 à 0. Il faut noter qu’à ce stade, MyControl4 a été libéré mais le WeakListener est toujours présent en mémoire. Sa libération ne sera effectué que lorsque l’événement sera appelé, la classe s’autodésabonnera toute seule de l’événement et pourra est collectée.

WeakEventList

J’ai ajouté dans slextensions une WeakEventList permettant de gérer une liste d’événements basés sur des WeakReference. A la place de stocker les événements par le processus standard de .Net, nous créons une liste de WeakReference directement sur les delegates abonnés.

Voila la déclaration de l’événement de ma class AppController.

        private WeakEventList<EventArgs> weakTestEvent;

 

        private event EventHandler<EventArgs> testEvent;

        public event EventHandler<EventArgs> TestEvent

        {

            add

            {

                if(UseWeakEvent)

                {

                    weakTestEvent.Event += value;

                }

                else

                {

                    testEvent += value;                   

                }

            }

            remove

            {

                if (UseWeakEvent)

                {

                    weakTestEvent.Event -= value;

                }

                else

                {

                    testEvent -= value;

                }

            }

        }

image

En cochant la case UseWeakEvent et en reproduisant le cas qui posait problème au début de ce post ( Add MyControl2, Remove, Force GC), on voit que la référence est bien libérée.

Vous trouvez plusieurs autres manières de créer des “weakevent” sur internet. Celle-ci est la seule qui marche en silverlight pour des appels à des fonctions privées. De nombreuses utilisent la réflexion pour pouvoir accéder à la fonction finale à appeler par l’événement, ceci n’est pas permit en silverlight si la déclaration est privée. Le mode MediumTrust de silverlight nous en empêche.

#    Comments [7] |
# Thursday, April 23, 2009

Silverlight Extensions

Comme vous le savez les 2 projets Silverlight Extensions et Silverlight Contrib sont en cours de fusion :

image

- Silverlight Extensions et Silverlight Contrib

- The Future of Silverlight Contrib

- MVPs Shine Silverlight Together at MVP Global Summit!

 

Pour l’occasion nous avons mis en place le nouveau site de Silverlight Extensions sous N2 CMS et le futur Blog de Silverlight Extensions sous BlogEngine.NET.

* En attendant que la fusion avance, n’oubliez pas d’aller sur les sites des deux projets Silverlight Extensions et Silverlight Contrib.

#    Comments [0] |
# Tuesday, April 21, 2009

France Télévisions – L’info en vidéo

Nouvelle version de l’application Silverlight L’info en vidéo.

Vous pouvez maintenant retrouver les vidéos des différentes émissions !

image

image

#    Comments [0] |
# Friday, April 17, 2009

Silverlight Extensions et Silverlight Contrib

Comme nous vous le disions dans un précédent post et comme vous avez pu le voir sur les sites respectifs des deux projets, les 2 projets sont en cours de fusion. Le nom du projet résultant de cette fusion a été publié par Page Brooks sur un son blog. Un vote était organisé et c’est le nom silverlight extensions qui a remporté la majorité des voix. Retrouvez le post de Page Brooks

image[1] 

En attendant que la fusion avance, n’oubliez pas d’aller sur le site web des deux projets. slextensions et silverlight contrib

#    Comments [0] |
# Tuesday, April 14, 2009

Utilisation des behaviors pour localiser une application silverlight ou WPF

Il y a quelques temps déjà, j’ai ajouté à slextensions une classe permettant de localiser simplement une application à partir d’attachedproperty. La mode étant aux behaviors, j’ai rajouté une classe permettant cette localisation à la branche SL3 de slextensions. Cette classe possède 4 propriétés :

  • Key : la clé de la ressource provenant de votre ResourceManager
  • PropertyName : Le nom de la propriété à localiser
  • ResourceManagerKey : La clé avec laquelle retrouver le ResourceManager dans les ressources de l’application
  • ConvertXaml : Si la resource contient du Xaml, permet d’instancier ce xaml par le XamlReader.

L’utilisation est très simple voici un exemple de localisation d’un texte

            <TextBlock  >

                <i:Interaction.Behaviors>

                    <SLExtensions_Interactivity:Localize Key="WelcomeMessage" PropertyName="Text" ResourceManagerKey="MyResource" />

                </i:Interaction.Behaviors>

            </TextBlock>

et d’un ContentControl

            <ContentControl Height="121" Width="244" Canvas.Left="25" Canvas.Top="206" >

                <i:Interaction.Behaviors>

                    <SLExtensions_Interactivity:Localize Key="Welcome" PropertyName="Content" ResourceManagerKey="MyResource" ConvertXaml="True"/>

                </i:Interaction.Behaviors>

            </ContentControl>

Le code de la classe :

using System;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Ink;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

using Microsoft.Expression.Interactivity;

using System.Resources;

using System.Globalization;

using System.Windows.Markup;

using SLExtensions.Globalization;

 

namespace SLExtensions.Interactivity

{

    public class Localize : Behavior<FrameworkElement>

    {

 

        private string key;

 

        public string Key

        {

            get

            {

                return this.key;

            }

 

            set

            {

                if (this.key != value)

                {

                    this.key = value;

                    Refresh();

                }

            }

        }

 

        private bool convertXaml;

 

        public bool ConvertXaml

        {

            get

            {

                return this.convertXaml;

            }

 

            set

            {

                if (this.convertXaml != value)

                {

                    this.convertXaml = value;

                    Refresh();

                }

            }

        }

 

 

        private DependencyProperty dependencyProperty;

 

        private string propertyName;

 

        public string PropertyName

        {

            get

            {

                return this.propertyName;

            }

 

            set

            {

                if (this.propertyName != value)

                {

                    this.propertyName = value;

                    this.dependencyProperty = null;

                    Refresh();

                }

            }

        }

 

        private string resourceManagerKey;

 

        public string ResourceManagerKey

        {

            get

            {

                return this.resourceManagerKey;

            }

 

            set

            {

                if (this.resourceManagerKey != value)

                {

                    this.resourceManagerKey = value;

                }

            }

        }

 

        private void Refresh()

        {

            if (AssociatedObject == null

                || string.IsNullOrEmpty(propertyName)

                || string.IsNullOrEmpty(Key)

                || string.IsNullOrEmpty(ResourceManagerKey))

                return;

 

            if (dependencyProperty == null)

            {

                Type t = AssociatedObject.GetType();

                var field = t.GetField(propertyName + "Property", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);

                if (field != null)

                {

                    dependencyProperty = field.GetValue(null) as DependencyProperty;

                }

            }

 

            if (dependencyProperty != null

                && Application.Current != null)

            {

                ResourceManager resourceManager = null;

                var obj = Application.Current.Resources[ResourceManagerKey];

                if (obj is ResourceLoader)

                {

                    resourceManager = ((ResourceLoader)obj).GetResourceManager();

                }

                else

                {

                    resourceManager = obj as ResourceManager;

                }

 

                var resourceValue = resourceManager.GetObject(Key, CultureInfo.CurrentCulture);

                if (convertXaml && resourceValue is string)

                {                   

                    resourceValue = XamlReader.Load((string)resourceValue);

                }

                AssociatedObject.SetValue(dependencyProperty, resourceValue);

            }

        }

 

        protected override void OnAttached()

        {

            Refresh();

            base.OnAttached();

        }

 

        protected override void OnDetaching()

        {

            base.OnDetaching();

        }

    }

}

#    Comments [0] |
# Tuesday, April 07, 2009

Les behavior en Silverlight 3 - MapState behavior

Exemple

Les behaviors introduits par blend 3 servent à étendre les fonctionnalités d’un contrôle à l’aide d’une nouvel élément que l’on peut poser graphiquement dans l’interface de blend. L’ajout de comportement n’est pas nouveau, c’est utilisé dans de nombreux projets (par exemple, la navigation deepzoom de slextensions est géré de cette manière), mais ici, l’intégration à blend est plutôt pratique et permet à un intégrateur de gérer du comportement sans écrire de code.

La classe MapState me permet de mapper l’état d’une propriété d’un contrôleur à un VisualState posé sur mon contrôle.

Ma classe contrôleur de test n’a rien de particulier. Voici sa définition.

    public class ApplicationController : INotifyPropertyChanged

    {

 

        #region INotifyPropertyChanged Members

 

        public event PropertyChangedEventHandler PropertyChanged;

 

        protected void OnPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

 

        #endregion

 

        private TestStates state;

        public TestStates State

        {

            get { return state; }

            set

            {

                if (state != value)

                {

                    state = value;

                    OnPropertyChanged(StatePropertyName);

                }

            }

        }

 

        public const string StatePropertyName = "State";

 

    }

J’instancie ce contrôleur en l’injectant dans les ressources de l’application

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            x:Class="TestBehavior.App"

            xmlns:controllers="clr-namespace:TestBehavior.Controllers"

            >

    <Application.Resources>

        <controllers:ApplicationController x:Key="appController" />

    </Application.Resources>

</Application>

Je rajoute les références qui vont bien à mon projet

image

Je peux maintenant rajoute mon behavior à l’aide de blend

image

Je remplie le mapping et la source de mon behavior avec blend

image

Le morceau de code qui change l’état du contrôleur.

        private void Button_Click(object sender, RoutedEventArgs e)

        {

            ApplicationController appController = Application.Current.Resources["appController"] as ApplicationController;

            appController.State = (TestStates) ((1 + (int)appController.State) % 3);

        }

Le code

Ma classe MapState hérite d’une classe ancêtre Behavior que vous trouverez dans l’assembly Microsoft.Expression.Interactivity.dll qui se trouve dans le dossier Libraries/Silverlight de Blend 3.

J’ai déclaré une propriété Source qui me sert à récupérer l’objet métier qui va me donner mon état et une propriété Property me donnant le nom de la propriété d’état. Ma source doit bien sur implémenter INotifyPropertyChanged pour que MapState soit notifiée du changement de propriété.
J’ai également une collection de MapStateMapping qui me fournisse un couple Valeur / VisualState.
Au changement de valeur sur ma source, je n’ai plus qu’à comparer par rapport aux valeurs de mapping est à déclancher le visualstate sur mon élément associé.

Le code complet de la classe :

namespace SLExtensions.Interactivity

{

    [ContentProperty("Mappings")]

    public class MapState : Behavior<FrameworkElement>

    {

        public MapState()

        {

            Mappings = new List<MapStateMapping>();

        }

 

        #region Source

 

        private PropertyInfo propertyInfo = null;

 

        public object Source

        {

            get

            {

                return (object)GetValue(SourceProperty);

            }

 

            set

            {

                SetValue(SourceProperty, value);

            }

        }

 

        /// <summary>

        /// Source depedency property.

        /// </summary>

        public static readonly DependencyProperty SourceProperty =

            DependencyProperty.Register(

                "Source",

                typeof(object),

                typeof(MapState),

                new PropertyMetadata((d, e) => ((MapState)d).OnSourceChanged((object)e.OldValue, (object)e.NewValue)));

 

        /// <summary>

        /// handles the SourceProperty changes.

        /// </summary>

        /// <param name="oldValue">The old value.</param>

        /// <param name="newValue">The new value.</param>

        private void OnSourceChanged(object oldValue, object newValue)

        {

            propertyInfo = null;

            INotifyPropertyChanged notifyingObject = oldValue as INotifyPropertyChanged;

            if (notifyingObject != null)

            {

                notifyingObject.PropertyChanged -= new PropertyChangedEventHandler(notifyingObject_PropertyChanged);

            }

            notifyingObject = newValue as INotifyPropertyChanged;

            if (notifyingObject != null)

            {

                notifyingObject.PropertyChanged += new PropertyChangedEventHandler(notifyingObject_PropertyChanged);

            }

            if (newValue != null && !string.IsNullOrEmpty(Property))

            {

                propertyInfo = newValue.GetType().GetProperty(Property);

            }

            RefreshState();

        }

 

        #endregion Source

 

        #region Property

 

        public string Property

        {

            get

            {

                return (string)GetValue(PropertyProperty);

            }

 

            set

            {

                SetValue(PropertyProperty, value);

            }

        }

 

        /// <summary>

        /// Property depedency property.

        /// </summary>

        public static readonly DependencyProperty PropertyProperty =

            DependencyProperty.Register(

                "Property",

                typeof(string),

                typeof(MapState),

                new PropertyMetadata((d, e) => ((MapState)d).OnPropertyChanged((string)e.OldValue, (string)e.NewValue)));

 

        /// <summary>

        /// handles the PropertyProperty changes.

        /// </summary>

        /// <param name="oldValue">The old value.</param>

        /// <param name="newValue">The new value.</param>

        private void OnPropertyChanged(string oldValue, string newValue)

        {

            if (Source == null)

                propertyInfo = null;

            else

                propertyInfo = Source.GetType().GetProperty(newValue);

 

            RefreshState();

        }

 

        #endregion Property

 

        public List<MapStateMapping> Mappings { get; private set; }

 

 

 

        void notifyingObject_PropertyChanged(object sender, PropertyChangedEventArgs e)

        {

            if(e.PropertyName == Property)

                RefreshState();

        }

 

        private void RefreshState()

        {

            // Do not refresh at desing time

            if (!HtmlPage.IsEnabled)

                return;

 

            if (Source != null && propertyInfo != null )

            {

                object propValue = propertyInfo.GetValue(Source, null);

 

                if (propValue == null)

                {

                    var nullMappings = from m in Mappings

                                       where m.Value == null

                                       || ((m.Value is string) && string.Empty.Equals(m.Value))

                                       select m.StateName;

 

                    try

                    {

                        SLExtensions.Controls.Animation.VisualState.GoToState(AssociatedObject, UseTransitions, nullMappings.ToArray());

                    }

                    catch

                    {

                    }

                }

                else

                {

                    MapStateMapping mapping = null;

                    foreach (var item in Mappings)

                    {

                        var value = item.Value;

                        if (value != null)

                        {

                            if (object.Equals(value, propValue))

                            {

                                mapping = item;

                                break;

                            }

 

                            if (propValue is IConvertible && value is IConvertible)

                            {

                                try

                                {

                                    var val2 = Convert.ChangeType(propValue, value.GetType(), CultureInfo.InvariantCulture);

                                    if (object.Equals(val2, value))

                                    {

                                        mapping = item;

                                        break;

                                    }

                                }

                                catch

                                {

                                }

 

                                try

                                {

                                    var val2 = Convert.ChangeType(value, propValue.GetType(), CultureInfo.InvariantCulture);

                                    if (object.Equals(val2, propValue))

                                    {

                                        mapping = item;

                                        break;

                                    }

                                }

                                catch

                                {

                                }

                            }

                        }

                    }

 

                    if (mapping != null)

                    {

                        try

                        {

                            SLExtensions.Controls.Animation.VisualState.GoToState(AssociatedObject, UseTransitions, mapping.StateName);

                        }

                        catch

                        {

                        }

                    }

                }

            }

        }

 

        /// <summary>

        ///

        /// </summary>

        public static readonly DependencyProperty UseTransitionsProperty = DependencyProperty.Register("UseTransitions", typeof(bool), typeof(MapState), new PropertyMetadata(true));

 

        /// <summary>

        /// True if transitions should be used for the state change.

        /// </summary>

        public bool UseTransitions

        {

            get { return (bool)this.GetValue(MapState.UseTransitionsProperty); }

            set { this.SetValue(MapState.UseTransitionsProperty, value); }

        }

 

        /// <summary>

        /// Hooks up necessary handlers for the state changes.

        /// </summary>

        protected override void OnAttached()

        {

            base.OnAttached();

 

            FrameworkElement element = this.AssociatedObject;

            if (element != null)

            {

                element.Loaded += new RoutedEventHandler(element_Loaded);

 

                RefreshState();

            }

            else

            {

                Dispatcher.BeginInvoke(delegate

                {

                    this.OnAttached();

                });

            }

        }

 

        void element_Loaded(object sender, RoutedEventArgs e)

        {

            RefreshState();

        }

    }

}

Les sources

En attendant de publier tout ça sur slextensions, vous pouvez télécharger le projet ici: 
Vous pouvez retrouver d’autres behavior sur le site de la gallery expression : http://gallery.expression.microsoft.com/

#    Comments [0] |
# Friday, April 03, 2009

silverlight 3 beta et silverlight 2 sur la même machine de dev

logo Travailler avec des versions beta de logiciels est parfois compliqué. Que faire avec les outils ? Est-ce que je les installe sur ma machine de développement, est-ce que je les installe sur une machine virtuelle ?

Vous trouverez ici : http://blogs.msdn.com/amyd/archive/2009/03/18/switching-from-silverlight-3-tools-to-silverlight-2-tools.aspx un petit script permettant de changer simplement la version des Silverlight tools utilisés par visual studio.

#    Comments [0] |
# Friday, March 13, 2009

Silverlight Contrib et Silverlight Extensions fusionnent

logo-slExt-ContrNous sommes fières d’annoncer aujourd’hui la fusion de Silverlight Contrib et Silverlight Extensions en un seul et unique projet ! Nous pensons que cette fusion apportera beaucoup de bénéfic es à la communauté. Cette combinaison permettra aux développeurs d’avoir un point unique pour rechercher des contrôles à intégrer dans leurs applications ainsi que pour en soumettre de nouveaux. Cette action réduira le temps passé dans chaque projet pour vous fournir des fonctionnalités équivalentes et nous permettra d’accélérer la cadence des releases.

Pendant la phase de consolidation du code, nous vous encourageons à nous soumettre vos retours ou problèmes à chaque projets. Nous fusionnerons les informations des deux projets lorsque le site commun sera ouvert et le nom final déterminé.

Quel nom allons-nous garder ? Cette décision vous appartient ! Vos votes détermineront le plus populaire. Assurez-vous que votre préférence soit prise en compte, votez ! Les votes seront acceptés jusqu’au 29 mars 2009 23:00 (GMT+1)

Nous vous tiendrons informé des évolutions sur chacun des blogs des 2 projets Silverlight Contrib et Silverlight Extensions.

Retrouvez ce post sur le site de Silverlight Contrib

Les équipes de slextensions et silverlight contrib.

#    Comments [0] |
# Friday, February 13, 2009

SLExtensions Converters – AlternateBackgroundConverter

Le projet SLExtensions commence à être assez conséquent. Je vais essayer de poster un peu plus régulièrement sur ce qu’il contient et compléter les exemples. Je commence donc cette série d’article par un des nombreux converter contenu dans le projet.

L’AlternateBackgroundConverter retourne un brush différent chaque fois que le converter est appelé.
Ce converter nécessite que la propriété ConverterParameter soit spécifiée lors du binding.
Le ConverterParameter peut être soit une string contenant une liste de couleurs séparées par des espaces soit une référence à un objet AlternateBackgroundConverterParameter.

  • Lorsqu’une string est passée, les couleurs peuvent être spécifiées au format argb sous forme hexadécimale (#RRGGBB ou #AARRGGBB) ou être un des nom de propriété existant dans la classe Colors (White, Red, Yellow, etc…)
  • Lorsqu’un AlternateBackgroundConverterParameter est passé, vous pouvez spécifier n’importe quel type de brush, SolidBrush, GradientBrush, VideoBrush, ImageBrush

 

<UserControl x:Class="SLExtensions.Showcase.PageAlternateConverter"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:sled="clr-namespace:SLExtensions.Data;assembly=SLExtensions"

   xmlns:scControllers="clr-namespace:SLExtensions.Showcase.Controllers;assembly=SLExtensions.Showcase"

  >

    <UserControl.Resources>

 

        <sled:AlternateBrushConverter x:Key="alternateConverter" />

 

        <sled:AlternateBrushConverterParameter x:Key="alternateParameter" >

            <sled:AlternateBrushConverterParameter.Brushes>

                <SolidColorBrush Color="White"/>

                <LinearGradientBrush StartPoint="0.45666,0.185989" EndPoint="1.22116,0.185989">

                    <LinearGradientBrush.RelativeTransform>

                        <TransformGroup>

                            <SkewTransform CenterX="0.45666" CenterY="0.185989" AngleX="0.135522" AngleY="0"/>

                            <RotateTransform CenterX="0.45666" CenterY="0.185989" Angle="82.8625"/>

                        </TransformGroup>

                    </LinearGradientBrush.RelativeTransform>

                    <GradientStop Color="#80FFFFFF" Offset="0"/>

                    <GradientStop Color="#808C8A8C" Offset="0.62345"/>

                    <GradientStop Color="#8019161A" Offset="1"/>

                </LinearGradientBrush>

                <SolidColorBrush Color="Gainsboro"/>

                <SolidColorBrush Color="#FFDD22"/>

            </sled:AlternateBrushConverterParameter.Brushes>

        </sled:AlternateBrushConverterParameter>

    </UserControl.Resources>

    <StackPanel x:Name="LayoutRoot" Background="White" >

        <TextBlock Text="Alternating brush converter"/>

        <ItemsControl ItemsSource="ABCDEFGH">

            <ItemsControl.ItemTemplate>

                <DataTemplate>

                    <Grid Background="{Binding Path='', Converter={StaticResource alternateConverter}, ConverterParameter={StaticResource alternateParameter}}">

                        <TextBlock Text="{Binding}" />   

                    </Grid>

                </DataTemplate>

            </ItemsControl.ItemTemplate>

        </ItemsControl>

 

        <ItemsControl ItemsSource="ABCDEFGH" Margin="0,40,0,0">

            <ItemsControl.ItemTemplate>

                <DataTemplate>

                    <Grid Background="{Binding Path='', Converter={StaticResource alternateConverter}, ConverterParameter='White Gray #FFDD22'}">

                        <TextBlock Text="{Binding}" />

                    </Grid>

                </DataTemplate>

            </ItemsControl.ItemTemplate>

        </ItemsControl>

    </StackPanel>

</UserControl>

#    Comments [0] |
# Saturday, January 31, 2009

Bonne Année 2009 !

Toute l’équipe d’UCAYA se joint à moi pour vous souhaiter une très bonne année !

Silverlight oblige nous avons un peu animé notre eCard ;-)

happynewyear2009-mailcard

#    Comments [0] |
# Wednesday, December 17, 2008

Projet Silverlight "Being the Big Boss"

Depuis le 8 décembre la version 1 de www.beingthebigboss.com est en ligne !

 

Il s’agit d’un jeu de simulation économique et d’entreprise, à “But récréatif et pédagogique : Mettez vous dans la peau d'un PDG d'une multinationale et construisez un empire reconnu et respecté !”.

Being the Big Boss est réalisé pour la partie client en Silverlight 2. Pour la partie serveur SQL Server 2008, LinqToEntities et WCF pour la communication Client/Serveur.

Quelques infos supplémentaires :

- Côté Silverlight il s’appuie sur la librairie SLExtensions ;-)

- Le modèle UML a été créé avec ArgoUML

- La génération du mapping est réalisé avec EF.Wizard

Pour vous donner un avant goût :

#    Comments [0] |
# Saturday, October 25, 2008

Partager des DataContracts entre WebServices avec Silverlight

Les différents webservices d’une même application ont parfois besoin de partager les mêmes structures de données. Par défaut, lors de l’ajout de ces webservices à la solution, Silverlight duplique les classes de données générées.

Imaginons un DataContract User retourné par un webservice Users.svc qui gère les utilisateurs et utilisé dans webservice Rights.svc qui gère les droits de l’application.

    [DataContract]

    public class User

    {

        [DataMember]

        public string FirstName { get; set; }

 

        [DataMember]

        public string LastName { get; set; }

 

    }

 

    [ServiceContract(Namespace = "")]

    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

    public class Users

    {

        [OperationContract]

        public User GetUsers()

        {

            return new User { FirstName = "Thierry", LastName = "Bouquain" };

        }

    }

 

    [ServiceContract(Namespace = "")]

    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

    public class Rights

    {

        [OperationContract]

        public User AssignUserRights(User user)

        {

            return user;

        }

    }

solution Pour partager le datacontract User dans les classes générées, il suffit de créer la même classe User avec le même namespace dans un project silverlight et de le référencer dans l’application silverlight.
Une fois les références des webservices mise à jours, la classe User ne sera plus générée.

Pour éviter de dupliquer les datacontracts, il est possible de créer un projet silverlight qui utilise les mêmes fichiers côté client et côté serveur.
Evidement, dans ce cas, le code du DataContract ne peux référencer des objets serveurs qui n’existent pas côté silverlight.

Je vous invite à regarder le projet attaché à ce post.

 

 

 

 

 

 

 

#    Comments [0] |
# Tuesday, October 07, 2008

Captcha en Silverlight

Encore un nouveau venu dans SLExtensions. Voici un contrôle de captcha qui se branche sur le service gratuit www.recaptcha.net.

Le principe

recaptcha-api-diagram 

  1. 1 L’utilisateur télécharge l’application silverlight qui contient le contrôle de captcha.
  2. 2 Le contrôle de captcha récupère une image plus une clé de cryptage du serveur d’image de www.recaptcha.net.
  3. 3 Le contrôle de captcha renvoie au serveur web (par POST, Get, Webservice, comme vous voulez), la clé de cryptage optenue auprès de www.recaptcha.net ainsi que les mots saisis par l’utilisateur.
  4. 4 Le serveur web fait un appel au serveur www.recaptcha.net en passant les données venues de l’utilisateur (mots + clé) plus une clé privée. Le serveur reCaptcha valide ou non le captcha. Le serveur fait ensuite (ou non) son traitement.
  5. 5 Retour vers l’utilisateur pour l’informer du résultat.

Le contrôle

<UserControl x:Class="SLExtensions.Showcase.PageRecaptcha"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:slec="clr-namespace:SLExtensions.Controls;assembly=SLExtensions.Controls"

   Width="400" Height="300">

    <StackPanel x:Name="LayoutRoot" Background="White">

        <slec:ReCaptcha x:Name="captcha" PublicKey="6LesLAMAAAAAACjPBtyjD80bwTowvEQrslT8bJvT" HorizontalAlignment="Center" VerticalAlignment="Center" >

            <slec:ReCaptcha.Verifier>

                <slec:ReCaptchaHttpPostVerifier Url="/VerifyCaptcha.aspx" Success="ReCaptchaHttpPostVerifier_Success" Failed="ReCaptchaHttpPostVerifier_Failed"/>

            </slec:ReCaptcha.Verifier>

        </slec:ReCaptcha>

    </StackPanel>

</UserControl>

Pour utiliser le contrôle, vous devez fournir un objet qui implémente l’interface IReCaptchaVerifier. C’est lui qui va se charger de faire l’appel au webservice vers votre serveur. Dans SLExtensions, j’ai ajouté une classe d’exemple qui fait un POST http des informations ainsi que la page aspx qui valide les informations auprès de recaptcha.

#    Comments [0] |
# Friday, October 03, 2008

DeepZoom facile

J’ai rajouté dans le projet SLExtensions une librairie permattant de gérer facilement vos galleries DeepZoom. Il rajoute grâce aux méthodes d’extensions des fonctions utiles comme le positionnement automatique de votre collection, la gestion de la roulette de la souris, le glisser du deepzoom, le zoom sur une image de la collection, etc…

<UserControl x:Class="SLExtensions.Showcase.PageDeepZoom"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:sledz="clr-namespace:SLExtensions.DeepZoom;assembly=SLExtensions.DeepZoom"

   >

    <Grid x:Name="LayoutRoot" Background="White">

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto"/>

            <RowDefinition/>

        </Grid.RowDefinitions>

 

        <StackPanel Orientation="Horizontal">

            <Button Content="Next" Click="Next_Click"/>

            <Button Content="Previous" Click="Previous_Click"/>

            <Button Content="All" Click="All_Click"/>

        </StackPanel>

 

        <MultiScaleImage x:Name="msi" Source="http://labs.ucaya.com/dznantes/dzc_output.xml"

                        Grid.Row="1"

                        sledz:DZExtensions.ArrangeOnFirstMotionFinished="True"

                        sledz:DZExtensions.IsMousePanEnabled="True"

                        sledz:DZExtensions.IsMouseWheelEnabled="True"/>

    </Grid>

</UserControl>

L’activation de la gestion de la souris ainsi que le positionnement automatique des images se fait par des AttachedProperty à déclarer sur le contrôle MultiScaleImage.
Dans cet exemple, j’ai rajouté 3 bouttons permettant de faire un simple slideshow des images deepzoom. Ils exécutent des fontions d’extensions disponibles dans le namespace SLExtensions.DeepZoom.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

using SLExtensions.DeepZoom;

 

namespace SLExtensions.Showcase

{

    public partial class PageDeepZoom : UserControl

    {

        public PageDeepZoom()

        {

            InitializeComponent();

        }

 

        private int collectionIndex = -1;

 

        private void Next_Click(object sender, RoutedEventArgs e)

        {

            DZContext context = msi.EnsureContext();

            collectionIndex = (collectionIndex + 1) % context.ImagesToShow.Count;

            msi.ZoomFullAndCenterImage(collectionIndex);

        }

 

        private void Previous_Click(object sender, RoutedEventArgs e)

        {

            DZContext context = msi.EnsureContext();

            collectionIndex = (collectionIndex + context.ImagesToShow.Count - 1) % context.ImagesToShow.Count;

            msi.ZoomFullAndCenterImage(collectionIndex);

        }

 

        private void All_Click(object sender, RoutedEventArgs e)

        {

            msi.ZoomCenter();

        }

    }

}

#    Comments [1] |
# Saturday, August 16, 2008

Animations AgTweener vs Storyboard

Ces deux manières d'animer ont un comportement différent lorsque l'application silverlight effectue des traitements qui font baisser le taux d'images par seconde.
Petite comparaison du mode de fonctionnement.

Fonctionnement du storyboard

Les storyboards sont basés sur le temps et adaptent les valeurs des animations en fonction de la progression de l'animation.  Si le temps d'assignation de la valeur ou le traitement induit (binding par exemple) est supérieur au frame rate, le storyboard va sauter les frames intermédiaires.

Fonctionnement d'AgTweener

AgTweener utilise un système de "timer" pour animer les objets. L'implémentation aurait pu avoir le même comportement que les storyboard, mais les concepteurs en ont décidé autrement. Le timer interne est basé sur un storyboard de 20ms qui est redémarré chaque fois que l'assignation des valeurs est terminé. Le timing est effectué en comptant le nombre de frame. Même si l'application effectue un traitement coûteux lors de l'assignation de la valeur, on est sur d'avoir une animation de la valeur, au dépend du respect du timing de l'animation.

Conclusion

Lorsqu'une application effectue des traitement coûteux, une animation faite par AgTweener peut donner une impression de fluidité comparé à une animation par storyboard qui va sauter des frames. Si le timing de l'application est important, il vaut mieux alors utiliser des storyboards.

#    Comments [0] |
# Friday, July 11, 2008

Silverlight FlowLayout animé

J’ai porté un exemple du Kevin's WPF Bag-o-Tricks dans SLExtensions.
Voici un petit exemple d’utilisation.

        <ItemsControl Grid.Row="1" ItemsSource="azertyuiopsdfghjklazertyuiopsdfghjklazertyuiopsdfghjklazertyuiopsdfghjklazertyuiopsdfgh” >

            <ItemsControl.ItemsPanel>

                <ItemsPanelTemplate>

                    <slec:AnimatingTilePanel />

                ItemsPanelTemplate>

            ItemsControl.ItemsPanel>

        ItemsControl>

div>
#    Comments [0] |

Silverlight DockPanel

SLExtensions ajoute maintenant un DockPanel à la liste de ses contrôles.

        <slec:DockPanel Grid.Row="1" LastChildFill="True">

            <Button Content="Top" slec:DockPanel.Dock="Top" Height="60" />

            <Button Content="Left" slec:DockPanel.Dock="Left" Width="60" />

            <Button Content="Right" slec:DockPanel.Dock="Right" Width="60" />

            <Button Content="Bottom" slec:DockPanel.Dock="Bottom" Height="60" />

            <Button Content="Fill" />

        slec:DockPanel>

div>
#    Comments [0] |

France Télévision

playerinfo France Télévision sort son “player info”. Il permet de revoir les journaux de toutes les chaines du groupe France Télévision. Vous pourrez maintenant regarder le journal de votre région même si vous êtes en déplacement à l’autre bout du monde. Ucaya a participé à la réalisation de ce player. Il est développé en Silverlight 2 et utilise la librairie SLExtensions.

#    Comments [0] |
# Sunday, June 29, 2008

Animer des propriétés non animables par Storyboard

Le moteur d'animation de silverlight ne permet d'animer que certains types de propriétés : des couleurs, des doubles et des points. Il n'est a priori pas simple d'animer une propriété comme Margin. En rusant un peu, on se rend compte qu'il est tout à fait possible de le faire. L'idée est de passer par une classe intermédiaire qui possède une propriété simple et de faire la conversion vers le type Thickness utilisé pour représenté une Margin. Afin de facilité l'utilisation de cette classe depuis le Xaml, elle hérite de Panel et peut donc être posée dans n'importe quel conteneur. Voici donc un petit exemple que vous retrouverez bien sur dans le projet SLExtensions.

La classe wrapper

namespace SLExtensions.Controls.Animation

{

    ...

 

    public class MarginWrapper : Panel

    {

        public MarginWrapper()

        {

            // Hide this control. It's just a wrapper and does not need to be shown in the GUI

            this.Visibility = Visibility.Collapsed;

            this.Loaded += new RoutedEventHandler(MarginWrapper_Loaded);

        }

 

        void MarginWrapper_Loaded(object sender, RoutedEventArgs e)

        {

            EnsureElement();

        }

 

        public string ElementName { get; set; }

 

        private FrameworkElement element;

 

        private void EnsureElement()

        {

            if (element == null)

            {

                element = this.FindName(ElementName) as FrameworkElement;

                if (element != null)

                {

                    Thickness margin = element.Margin;

                    if (margin != null)

                    {

                        MarginLeft = margin.Left;

                        MarginTop = margin.Top;

                        MarginRight = margin.Right;

                        MarginBottom = margin.Bottom;

                    }

                }

            }

        }

 

        #region MarginLeft

 

        public double MarginLeft

        {

            get

            {

                return (double)GetValue(MarginLeftProperty);

            }

 

            set

            {

                SetValue(MarginLeftProperty, value);

            }

        }

 

        /// <summary>

        /// MarginLeft depedency property.

        /// </summary>

        public static readonly DependencyProperty MarginLeftProperty =

            DependencyProperty.Register(

                "MarginLeft",

                typeof(double),

                typeof(MarginWrapper),

                new PropertyMetadata((d, e) => ((MarginWrapper)d).OnMarginLeftChanged((double)e.OldValue, (double)e.NewValue)));

 

        /// <summary>

        /// handles the MarginLeftProperty changes.

        /// </summary>

        /// <param name="oldValue">The old value.</param>

        /// <param name="newValue">The new value.</param>

        private void OnMarginLeftChanged(double oldValue, double newValue)

        {

            EnsureElement();

            if (element != null)

            {

                Thickness margin = element.Margin;

                if (margin == null)

                    margin = new Thickness();

 

                margin.Left = newValue;

                element.Margin = margin;

            }

        }

 

        #endregion MarginLeft

 

...

 

    }

}

Un exemple de Xaml

<UserControl x:Class="SLExtensions.Showcase.PageAnimation"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:anim="clr-namespace:SLExtensions.Controls.Animation;assembly=SLExtensions.Controls"

   xmlns:slei="clr-namespace:SLExtensions.Input;assembly=SLExtensions"

   >

    <UserControl.Resources>

        <Storyboard x:Name="anim1">

            <DoubleAnimation Storyboard.TargetName="marginWrapper1" Storyboard.TargetProperty="MarginLeft" To="150" Duration="0:00:03"/>

        </Storyboard>

    </UserControl.Resources>

    <StackPanel x:Name="LayoutRoot" Background="White">

        <StackPanel Orientation="Horizontal">

            <Button Content="Start" slei:CommandService.Command="BeginStoryboard" slei:CommandService.CommandParameter="anim1" />

            <Button Content="Stop" slei:CommandService.Command="StopStoryboard" slei:CommandService.CommandParameter="anim1"/>

                <Grid Width="400" Height="100">

                    <anim:MarginWrapper x:Name="marginWrapper1" ElementName="rect1" />

                    <Rectangle x:Name="rect1" Fill="Red" Width="50" Height="50" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="50,0,0,0" />

                </Grid>

            </StackPanel>

    </StackPanel>

</UserControl>

#    Comments [0] |
# Saturday, June 28, 2008

Silverlight Extensions

Vous trouverez les exemples de code que je poste sur ce blog dans un projet nommé SLExtensions qui est disponible sur CodePlex. En plus des exemples de codes, vous trouverez quelques contrôles silverlight comme un TreeView ou un StackPanel virtualisé. Un mini showcase est visible ici : http://labs.ucaya.com/slextensions

#    Comments [0] |

Envoyer un formulaire html en POST avec Silverlight

Je vous propose une méthode d'extension simple qui permet d'envoyer un formulaire vers une page html. Le beta 2 de silverlight nous simplifie la vie avec la fonction UploadStringAsync. Il ne reste plus que l'encodage des données et le content type à assigner.

Voici la méthode d'extension

    /// <summary>

    /// Method extensions for SLExtension framework

    /// </summary>

    public static class SLExtension

    {

 

....

 

        #region WebClient

        /// <summary>

        /// Sends an HTML form. The request is sent using POST method

        /// </summary>

        /// <param name="webclient">The webclient.</param>

        /// <param name="uri">The URI of the resource to receive the file. </param>

        /// <param name="data">The form data to upload.</param>

        public static void SendHtmlForm(this WebClient webclient, Uri uri, IEnumerable<KeyValuePair<string, string>> data)

        {

            StringBuilder dataBuilder = new StringBuilder();

            int cnt = 0;

            foreach (var item in data)

            {

                if (cnt > 0)

                {

                    dataBuilder.Append('&');

                }

 

                dataBuilder.Append(item.Key);

                dataBuilder.Append('=');

                dataBuilder.Append(HttpUtility.UrlEncode(item.Value));

            }

 

            webclient.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";

            webclient.UploadStringAsync(uri, dataBuilder.ToString());

        }

 

        /// <summary>

        /// Sends an HTML form. The request is sent using POST method

        /// </summary>

        /// <param name="webclient">The webclient.</param>

        /// <param name="uri">The URI of the resource to receive the file. </param>

        /// <param name="data">The form data to upload.</param>

        /// <param name="userToken">user state</param>

        public static void SendHtmlForm(this WebClient webclient, Uri uri, IEnumerable<KeyValuePair<string, string>> data, object userToken)

        {

            StringBuilder dataBuilder = new StringBuilder();

            int cnt = 0;

            foreach (var item in data)

            {

                if (cnt > 0)

                {

                    dataBuilder.Append('&');

                }

 

                dataBuilder.Append(item.Key);

                dataBuilder.Append('=');

                dataBuilder.Append(HttpUtility.UrlEncode(item.Value));

            }

 

            webclient.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";

            webclient.UploadStringAsync(uri, "POST", dataBuilder.ToString(), userToken);

        }

        #endregion WebClient

        #endregion Public Methods

    }

#    Comments [0] |

Unload des contrôles en Silverlight

Il est parfois nécessaire d'être notifié lorsqu'un contrôle n'est plus dans l'arbre graphique de silverlight. Il n'existe pas à l'heure actuelle (c'est à dire dans la beta 2) d'événement unload, cependant, l'événement LayoutUpdated est levé sur les contrôles lorsqu'ils sont enlevés de leur parent. Voici un petit exemple de code. Notez au passage l'utilisation des méthodes d'extension.

namespace SLExtensions

{

    using System;

    using System.Text;

    using System.Windows;

    using System.Windows.Browser;

    using System.Windows.Controls;

    using System.Windows.Documents;

    using System.Windows.Ink;

    using System.Windows.Input;

    using System.Windows.Interop;

    using System.Windows.Media;

    using System.Windows.Media.Animation;

    using System.Windows.Shapes;

    using System.Collections.Generic;

 

    /// <summary>

    /// Method extensions for SLExtension framework

    /// </summary>

    public static class SLExtension

    {

       ...

 

        /// <summary>

        /// Determines whether an element is in the visual tree of the current application.

        /// </summary>

        /// <param name="element">The element.</param>

        /// <returns>

        ///    <c>true</c> if element paramter is in visual tree otherwise, <c>false</c>.

        /// </returns>

        public static bool IsInVisualTree(this FrameworkElement element)

        {

            return IsInVisualTree(element, Application.Current.RootVisual as FrameworkElement);

        }

 

        /// <summary>

        /// Determines whether an element is in the visual tree of a given ancestor.

        /// </summary>

        /// <param name="element">The element.</param>

        /// <param name="ancestor">The ancestor.</param>

        /// <returns>

        ///    <c>true</c> if element paramter is in visual tree otherwise, <c>false</c>.

        /// </returns>

        public static bool IsInVisualTree(this FrameworkElement element, FrameworkElement ancestor)

        {

            FrameworkElement fe = element;

            while (fe != null)

            {

                if (fe == ancestor)

                    return true;

                fe = fe.Parent as FrameworkElement;

            }

            return false;

        }

 

       ...

    }

}

 

<UserControl x:Class="SLExtensions.Showcase.IsInVisualTree"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <Rectangle x:Name="rect" Fill="Cornsilk" LayoutUpdated="rect_LayoutUpdated" />       

        <Button Content="Remove rect" Height="40" VerticalAlignment="Bottom" HorizontalAlignment="Center" Width="100" Click="Button_Click" />

    </Grid>

</UserControl>

 

using SLExtensions;

 

namespace SLExtensions.Showcase

{

    public partial class IsInVisualTree : UserControl

    {

        public IsInVisualTree()

        {

            InitializeComponent();

        }

 

        private void Button_Click(object sender, RoutedEventArgs e)

        {

            LayoutRoot.Children.Remove(rect);

        }

 

        private void rect_LayoutUpdated(object sender, EventArgs e)

        {

            if (!rect.IsInVisualTree())

            {

                // Handle unload behavior

            }

        }

    }

}

xcvcx

#    Comments [0] |
# Friday, June 13, 2008

Projet reMIX 08

constellation Vous trouverez ci-dessous les liens vers les vidéos d'un projet Silverlight 2 réalisé par mes soins pour le compte d'un de nos clients. Ce système de réservation en ligne bénéficie d'une grande fluidité d'utilisation et s'appuie sur les images cartographiques de virtual earth.

 

Video 1 - Présentation du client et du produit

Video 2 - Retours des tests utilisateurs

#    Comments [0] |
# Wednesday, April 30, 2008

Une RichTextBox en Silverlight

Michael Sync a publié sur son blog et sur CodePlex un Rich Text Editor en silverlight. Je ne l'ai pas encore testé, mais cela semble très prometteur.

rte

#    Comments [0] |

Conditions d'utilisation du serveur de tuiles VirtualEarth

Dans un billet précédent, j'ai présenté un module permettant d'afficher des cartes VirtualEarth en Silverlight. Ce module requête directement le serveur de tuile chez Microsoft sans utiliser le sdk javascript fourni par MS et du coup ne respecte pas la licence d'utilisation de VirtualEarth. Ce matin, un billet sur le blog virtual earth explique comment légaliser cet accès. Il suffit d'insérer un identifiant reçu par webservice lors de l'appel des tuiles.
Vous trouverez donc bientôt une nouvelle version de mon module tenant compte de cet identifiant.

#    Comments [0] |
# Wednesday, April 23, 2008

Cartographie en silverlight

layerhostJe poste sur le labs un début de contrôle de gestion de calques. Le but de ce contrôle est de pouvoir afficher des calques, zoomer, se déplacer dedans, afficher dynamiquement des données sur les nouvelles zones visibles. Ça ressemble furieusement à de la cartographie tout ça. C'est pourquoi les premiers calques que j'ai développés sont des calques Googlemap et Virtual Earth. Les premiers tests sont visibles ici : http://labs.ucaya.com/layerhost/
Ce contrôle devrait bientôt rejoindre une librairie qui sera téléchargeable sur CodePlex

#    Comments [0] |
# Friday, April 18, 2008

Thierry on the reMIX 08 Paris

Vous ne trouvez pas qu'il se la pète ? ;-) PIC-0053

Bon c'est vrai il peut, il a vraiment fait un super taf !

#    Comments [0] |
# Wednesday, April 02, 2008

Identification InfoCard (CardSpace) avec Silverlight2

cardspace Voila la conversion du sample js en Silverlight. L'appel à la fonction GetToken lance l'interface InfoCard et retourne le xml d'identification.

InfoCardSample.zip (19,32 KB)
#    Comments [0] |

Animer du HTML avec Silverlight 2

Silverlight possède un système d'animation très poussé. L'idée de ce sample est d'utiliser les storyboards pour agir sur des éléments du DOM.
Le principe est le même que pour le "game loop" d'un jeu. Tous les x millisecondes, on va agir sur les éléments à animer. On récupère la position et la taille d'un élément silverlight qui va servir de modèle et on les applique à l'élément du DOM.

Le projet :

La classe HtmlAnimation est en charge du "game loop". Elle possède une collection de HtmlAnimationPair. Les HtmlAnimationPair font la liaison entre l'élément silverlight et l'élément du DOM.

Site web de test

HtmlAnimation.zip (13,68 KB)
#    Comments [2] |
# Thursday, February 21, 2008

XamlTune Live

xamltuneA live version of xamltune has been released on our web site. This tool is intensively used by our development team. Svg graphics are converted in Xaml and the result can be optimized in several ways.

XamlTune sources and binaries can be downloaded on the codeplex page.

Live version can be tested in our labs area.

#    Comments [0] |
# Friday, February 08, 2008

XamlTune on CodePlex

XamlTune is now on codeplex. Have fun.
Untitled
#    Comments [2] |
# Wednesday, February 06, 2008

VisioExportToXAML

Saveen Reddy has released his visio export plugin on codeplex. He is using my XamlTune export library.

I've corrected XamlTune to render its last sample.
Untitled

#    Comments [0] |
# Monday, January 14, 2008

Produit d'avenir ?

La société Cynergy Labs regarde trop Minority Report. Ils ont utilisé la wii-mote pour et une paire de gants pour controler une application qui ressemble à Surface.
Ca ouvre pas mal de possibilités pour de nouvelles applications !

Une video plus longue : http://labs.cynergysystems.com/Silverlight.html

#    Comments [1] |
# Wednesday, December 19, 2007

Tafiti sous licence MS-PL

tafiti Tafiti est un des premiers projets Silverlight apparut sur le net. C'est une interface graphique plugguée au moteur de recherche live.com.

Ce projet fait maintenant parti des Windows Live Quick Application. Ce sont des petits exemples concrets qui expliquent comment utiliser la plateforme windows live.

Tafiti_Search_Visualization

#    Comments [0] |
# Saturday, December 08, 2007

Convertion Svg vers Xaml

XamlTune Si la plateforme .Net supportant le Xaml est gratuite, il n'en est pas de même des outils pour développer pour cette plateforme. Je ne parle pas ici du code, mais de quoi faire du desin Xaml. Pour transformer du svg en xaml, il n'existe que peu de logiciels.
WPF-Graphics - Paste2Xaml is a clipboard or metafiles into xaml
et Adobe Illustrator to XAML Export à ma connaissance. Je vous propose ici un petit utilitaire libre de droits pour générer faire ce travail. Il est basé sur SharpVector pour lire le svg et génère du xaml pour wpf ou silverlight. Je mets au passage le lien vers InkScape qui permet de travailler les fichiers svg.

Mise à jour 2007/12/13: Corrections sur les dégradés radiaux. La case à cocher "Canvas as Path Bounding box" reste encore buggué.

Mise à jour 2007/12/15: Ajout de textbox de visualisation et d'édition du svg/xaml. Corrections de bugs. Ajout d'un treeview de visualisation des éléments xaml.

Télécharger

#    Comments [0] |
# Friday, December 07, 2007

Blend 2 December Preview et Blend sp1

boxShot_Blend Une nouvelle CTP de Blend 2 est disponible sur le site de Microsoft. Quelques corrections de bugs et le support des solutions VS2008 RTM.

Téléchargement : Blend 2
Blend sp1

#    Comments [0] |
# Thursday, November 29, 2007

Silverlight 2.0

La liste des fonctionnalités de Silverlight 2.0 (précédemment Silverlight 1.1) vient d' être annoncée de manière non officielle sur plusieurs blogs. Silverlight se rapproche de plus en plus de WPF. (Databinding, Contrôles, Layout, ...) Devant toutes ces fonctionnalités, Microsoft a renommé Silverlight 1.1 en Silverlight 2.0

source : http://blogs.msdn.com/chabrook/archive/2007/11/29/silverlight-announcements-2-0-expected-to-go-beta-in-q1.aspx

#    Comments [0] |

Microsoft Download Center - Silverlight

UntitledMicrosoft refait son site de téléchargement en silverlight. Il n'est pas encore en production, mais vous pouvez le tester ici.

#    Comments [0] |
# Tuesday, November 27, 2007

Silverlight 1.1 Tools Alpha pour VS2008

Je n'ai pas fais de post à ce sujet, mais vous aurez remarqué que visual studio 2008 (aka VS2008 ou orcas) est sorti récemment. Le petit addin permettant de coder en silverlight 1.1 et de debugger ce code n'était pas compatible avec la version finale. C'est maintenant chose corrigée.

source: http://weblogs.asp.net/scottgu/archive/2007/11/26/silverlight-1-1-tools-alpha-for-visual-studio-2008-available-for-download.aspx
download: microsoft

#    Comments [0] |
# Thursday, November 08, 2007

Silverlight physics engine

physics

La gestion des effets physiques dans les jeux m'a toujours impressionné. Voici une démonstration d'un moteur qui tourne sous XNA ou silverlight 1.1. Ce moteur est hébergé sur codeplex.

Les liens :

#    Comments [0] |
# Thursday, October 25, 2007

Silverlight Tour - Nantes

PIC-0010Hier se déroulait la session de Nantes du silverlight tour.
Cette présentation avait pour but d'expliquer les fonctionnalités de la version 1.0 ainsi que de la version 1.1 du framework.

Cette présentation vise un public plutôt novice sur silverlight. Si vous avez déjà bidouillé avec silverlight, la présentation repasse sur la majorité des fonctionnalités.
Le bon points de la présentation sont les conseils sur comment bien mettre en place un projet silverlight, la présentation d'un projet réel (quicksilver) et les pièges à éviter.
A noter la démonstration du Silverlight Control Toolkit qui semble un bon point de départ pour une nouvelle application.

La démonstrations ont présenté la gamme Expression de microsoft et particulièrement deux produits. Expression Blend2 qui est l'atelier de design et d'animation de silverlight et Expression Encoder qui permet de compresser les vidéos pour être utilsables par silverlight.

Comme d'habitude, certaines personnes de l'assistance ont joué les blasés en qualifiant la version 1.0 de coup de pub ou de sans intérêt en attendant la version 1.1. Je ne suis pas de cet avis.

  • Toute la partie de rendu vectorielle va permettre d'intégrer plus facilement les travaux des infographistes.  
  • Cette première version va (comme le soulignait Christophe Lauer) permettre une démocratisation du plugin nécessaire à la visualisation du contenu silverlight.
  • La gestion de la video devient un jeu d'enfant

L'après midi fut très agréable. Je tiens à souligner la qualité des speakers de microsoft. Ils ne sont intéressant et savent maintenir leur auditoire en haleine. Nous sommes repartis avec une version d'evaluation de la gamme Expression

PIC-0008  PIC-0009

#    Comments [0] |
# Sunday, October 14, 2007

Diagrammes de classes

UcaModeler

Dans la sections produits du site se trouve un test de silverlight 1.1. Le but de ce test est de réaliser un éditeur de diagrammes de classes.
Les technologies utilisées ici sont

Ce n'est encore un premier jet mais je pense qu'il est possible d'arriver à quelque chose d'utilisable assez rapidement.

Pour tester, c'est par ici

#    Comments [0] |
# Wednesday, September 19, 2007

Silverlight 1.1 et les resources de langue

La version 1.1 de silverlight permet d'utiliser les fichiers .resx dans le code compilé comme n'importe quel autre projet. A l'heure actuel, Orcas ne reconnait pas encore qu'il utilise un projet silverlight et génère des attributs qui n'existent pas sur la classe associée. Pour passer la compilation, il suffit donc de recréer les classes qui manquent. 

namespace System.CodeDom.Compiler
{
  
public class GeneratedCodeAttribute : Attribute     
   {     
     
public GeneratedCodeAttribute(string a, string b) { }
   }
}

namespace System.Diagnostics.CodeAnalysis
{
  
public class SuppressMessageAttribute : Attribute  
   {
     
public SuppressMessageAttribute(string a, string b) { }
   }
}
     
namespace System.ComponentModel
{
  
public class EditorBrowsableAttribute : Attribute
   {
     
public EditorBrowsableAttribute(EditorBrowsableState a) { }
   }
  
public enum EditorBrowsableState { Advanced }
}

#    Comments [0] |