# Thursday, July 31, 2008

UCAYA Tour Next 1

::Ile de la Réunion::

3-small  au Piton des neiges : 3070m d' altitude !

#    Comments [0] |

UCAYA Tour

::Ile de la Réunion::

C'est parti !

1-small 2-small

à la plage...

#    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] |
# Saturday, July 05, 2008

MVP isé

Me voici élevé au rang de MVP Client App Dev. J'ai reçu hier mon petit package MVP en provenance des USs. Je vous fais profiter de son contenu. En plus du diplôme, j'ai reçu un set bluetooth contenant une paire d'écouteurs, un dongle et une souris MoGo.

Je suis très fier de faire parti des 173 MVPs français actifs de 2008 et je remercie tous ceux qui m'ont permis de le devenir.

PIC-0024 PIC-0025 PIC-0026

#    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] |
# Tuesday, May 27, 2008

Silverlight Command pattern et AttachedProperty

Les AttachedProperty

Ce type de propriété permet d'enrichir les propriétés existantes d'un objet. Ce sont des propriétés qui n'ont pas forcément de sens au niveau du contrôle lui-même, mais qui en ont au vu d'un contexte externe. Les AttachedProperty les plus connues sont Canvas.Left, Canvas.Top, Grid.Column et Grid.Row. Vous remarquerez que la propriété colonne n'a aucun sens sur un contrôle en dehors du contexte de la grille.

Ces AttachedProperty nous permettent d'étendre le comportement de nos contrôles. Nikhilk nous donne un exemple d'implémentation d'un framework de comportement sur son blog.

Le Command pattern

Ce pattern a pour but de séparer le comportement de la partie IHM. L'idée est de ne plus s'attacher directement aux événements des contrôles et de passer par un objet Command qui va faire la liaison entre le comportement et la saisie des utilisateurs.
Vous trouverez une bonne description du pattern Command en WPF sur le site de microsoft. Cette séparation permet de pouvoir déclencher l'action depuis l'IHM mais aussi depuis d'autres classes métiers.

Le code

La classe centrale est CommandService. Elle défini les AttachedProperty, c'est elle qui devra être référencée dans le xaml pour relier un contrôle à une commande.

<UserControl  xmlns="http://schemas.microsoft.com/client/2007"

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

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

...

        <Button Content="Open" Width="50" Height="30"

                      sle:CommandService.Command="Open"

                      sle:CommandService.CommandParameter="{Binding OpenFileInfo, Source={StaticResource controller}}" />

 

...

</UserControl>

Dans cet exemple, le bouton "Open" est bindé à la commande Open. On passe en paramètre à la commande un object OpenFileInfo qui est stocké sur le contrôleur de la page. Il sert à passer les paramètres d'exécution de la commande.

Du coté métier, le contrôleur de la page s'attache à l'événement Executed de la commande

...

 TestCommands.OpenCommand.Executed += new ExecutedEventHandler(OpenCommand_Executed);

...

void OpenCommand_Executed(object sender, ExecutedEventArgs e)

{

    OpenFileDialogInfo info = e.Parameter as OpenFileDialogInfo;

    if (info != null)

    {

        using (OpenFileDialog ofd = new OpenFileDialog())

        {

            ofd.EnableMultipleSelection = info.EnableMultipleSelection;

            ofd.Filter = info.Filter;

            ofd.ShowDialog();

        }

    }

}

 

Téléchargements Sources

#    Comments [0] |