# 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] |
# Monday, March 23, 2009

MIX09

MIX09 à Las Vegas, nous y étions !

MIX09

De retour en france, voici une petite liste de liens en français dont les blogs des frenchies avec qui nous avons eu la chance de vivre cette magnifique expérience :

Pierre Lagarde : http://blogs.msdn.com/pierlag/

Dick Lantim : http://blogs.msdn.com/dicklant/

Christophe Lauer : http://blogs.msdn.com/clauer/

David Rousset : http://blogs.msdn.com/davrous/

LeMixer : http://lemixer.fr/

#    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] |
# Thursday, February 05, 2009

UCAYA Goodies

On ne l’arrête plus ! Vous pouvez maintenant retrouver les premiers goodies UCAYA sur le labs : http://labs.ucaya.com/goodies.aspx.

#    Comments [1] |

L’équipe s’est agrandie

UCAYA prend une réelle dimension graphique !

Depuis maintenant quelques mois JBay a rejoint l’équipe d’UCAYA. C’est maintenant lui qui est en charge de la Création visuelle et du Design.

Bienvenue à JBay !

#    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] |
# Tuesday, January 06, 2009

UCAYA Tour Next 6

::Au Sénégal::

Après un moment sans nouvelle photo, le voyage continue !

UCAYA-Tour-Senegal-1 UCAYA-Tour-Senegal-2

UCAYA-Tour-Senegal-3 UCAYA-Tour-Senegal-4

Nous vous invitons, heureux possesseurs de LA casquette UCAYA (100 exemplaires seulement existent ;-)), à nous envoyer des photos de tous les endroits merveilleux et/ou insolites que vous avez pu visiter avec votre casquette !

#    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] |