Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Benjamin Roux

Silverlight Expert - Silverlight Fan - MVP Client App Dev

Actualités

  • Mon statut Live Messenger :





    View Benjamin Roux's profile on LinkedIn

    Benjamin Roux's Facebook Profile


    MVP Blog Badge.
[Silverlight] Gestion du menu contextuel

silverlight Bonjour à tous,

Une question qui revient souvent sur les forums dédiés à Silverlight est la gestion du menu contextuel (clic droit). La réponse actuelle est qu’il n’est pas possible nativement de surcharger les menu contextuel à la manière de Flash. Il semblerait qu’il faille attendre une future version de Silverlight…

En revanche je vais ici vous montrer une solution “passable” permettant de passer outre le clic droit classique. Il faut savoir que le code suivant fonctionne correctement sous IE mais pose quelques soucis sous Firefox. En effet, sous ce dernier, le menu classique s’affiche suivi du menu custom. Si quelqu’un connait une solution il peut se manifester dans les commentaires.

Pour rendre le tout facilement utilisable j’ai créé une classe RightClickService permettant de créer facilement des menu contextuels pour toute sorte de contrôle.

Tout d’abord voici le ContextMenuItem et le ContextMenu.

[TemplateVisualState(Name = "Normal", GroupName = "CommonStates"),
TemplateVisualState(Name = "Focused", GroupName = "FocusStates"),
TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates"),
TemplateVisualState(Name = "Disabled", GroupName = "CommonStates"),
TemplateVisualState(Name = "Unselected", GroupName = "SelectionStates"),
TemplateVisualState(Name = "Selected", GroupName = "SelectionStates"),
TemplateVisualState(Name = "SelectedUnfocused", GroupName = "SelectionStates"),
TemplateVisualState(Name = "Unfocused", GroupName = "FocusStates")]
public class ContextMenuItem : ContentControl
{
    public event MouseButtonEventHandler Click;
 
    public ContextMenuItem()
    {
        this.DefaultStyleKey = typeof(ContextMenuItem);
        this.MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e)
        {
            if (Click != null) Click(this, e);
        };
    }
 
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        VisualStateManager.GoToState(this, "Normal", false);
    }
 
    protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
    {
        if (!e.Handled)
        {
            base.OnMouseLeftButtonUp(e);
            e.Handled = true;
            if (RightClickService.Popup != null) RightClickService.Popup.IsOpen = false;
        }
    }
 
    protected override void OnMouseEnter(MouseEventArgs e)
    {
        base.OnMouseEnter(e);
        VisualStateManager.GoToState(this, "MouseOver", false);
    }
 
    protected override void OnMouseLeave(MouseEventArgs e)
    {
        base.OnMouseLeave(e);
        VisualStateManager.GoToState(this, "Normal", false);
    }
}

Il s’agit tout simplement d’un contrôle simple ressemblant à un ListBoxItem. J’ai également créé un event Click se déclanchant lors d’un MouseLeftButtonDown.

La thème du contrôle est le suivant :

<ResourceDictionary
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:ContextMenu"    
  xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">
    <Style TargetType="local:ContextMenu">
        <Setter Property="Padding" Value="1"/>
        <Setter Property="Background" Value="#FFFFFFFF" />
        <Setter Property="Foreground" Value="#FF000000"/>
        <Setter Property="HorizontalContentAlignment" Value="Left" />
        <Setter Property="VerticalContentAlignment" Value="Top" />
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="TabNavigation" Value="Once" />
        <Setter Property="BorderBrush">
            <Setter.Value>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FFA3AEB9" Offset="0"/>
                    <GradientStop Color="#FF8399A9" Offset="0.375"/>
                    <GradientStop Color="#FF718597" Offset="0.375"/>
                    <GradientStop Color="#FF617584" Offset="1"/>
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:ContextMenu">
                    <Border CornerRadius="2" 
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <ItemsPresenter />
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
 
    <Style TargetType="local:ContextMenuItem">
        <Setter Property="Padding" Value="3" />
        <Setter Property="HorizontalContentAlignment" Value="Left" />
        <Setter Property="VerticalContentAlignment" Value="Top" />
        <Setter Property="Background" Value="Transparent" />
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:ContextMenuItem">
                    <Grid Background="{TemplateBinding Background}">
                        <vsm:VisualStateManager.VisualStateGroups>
                            <vsm:VisualStateGroup x:Name="CommonStates">
                                <vsm:VisualState x:Name="Normal" />
                                <vsm:VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="fillColor" Storyboard.TargetProperty="Opacity" Duration="0" To=".35"/>
                                    </Storyboard>
                                </vsm:VisualState>
                                <vsm:VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="contentPresenter" Storyboard.TargetProperty="Opacity" Duration="0" To=".55" />
                                    </Storyboard>
                                </vsm:VisualState>
                            </vsm:VisualStateGroup>
                            <vsm:VisualStateGroup x:Name="SelectionStates">
                                <vsm:VisualState x:Name="Unselected" />
                                <vsm:VisualState x:Name="Selected">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="fillColor2" Storyboard.TargetProperty="Opacity" Duration="0" To=".75"/>
                                    </Storyboard>
                                </vsm:VisualState>
                            </vsm:VisualStateGroup>
                            <vsm:VisualStateGroup x:Name="FocusStates">
                                <vsm:VisualState x:Name="Focused">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Visibility" Duration="0">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </vsm:VisualState>
                                <vsm:VisualState x:Name="Unfocused"/>
                            </vsm:VisualStateGroup>
                        </vsm:VisualStateManager.VisualStateGroups>
                        <Rectangle Fill="LightGray" IsHitTestVisible="False" RadiusX="1" RadiusY="1" />
                        <Rectangle x:Name="fillColor" Opacity="0" Fill="#FFBADDE9" IsHitTestVisible="False" RadiusX="1" RadiusY="1"/>
                        <Rectangle x:Name="fillColor2" Opacity="0" Fill="#FFBADDE9" IsHitTestVisible="False" RadiusX="1" RadiusY="1"/>
                        <ContentPresenter
                    x:Name="contentPresenter"
                    Content="{TemplateBinding Content}"
                    ContentTemplate="{TemplateBinding ContentTemplate}"
                    HorizontalAlignment="Left"
                    Margin="{TemplateBinding Padding}"/>
                        <Rectangle x:Name="FocusVisualElement" Stroke="#FF6DBDD1" StrokeThickness="1" Visibility="Collapsed" RadiusX="1" RadiusY="1" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
 
</ResourceDictionary>

Le ContextMenu :

public class ContextMenu : ItemsControl
{
    public ContextMenu()
    {
        base.DefaultStyleKey = typeof(ContextMenu);
    }
 
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
    }
 
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new ContextMenuItem();
    }
 
    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return (item is ContextMenuItem);
    }
}

Ce contrôle hérite de ItemsControl, et surcharge les méthodes GetContainerForItemOverride et IsItemItsOwnContainerOverride pour définir le contrôle à utiliser pour l’affichage si on n’utilise pas directement un ContextMenuItem.

Voici maintenant la classe utile : RightClickService.

public class RightClickService
{
    private static FrameworkElement mRootVisual = null;
 
    internal static FrameworkElement RootVisual
    {
        get
        {
            SetRootVisual();
            return mRootVisual;
        }
    }
 
    private static void SetRootVisual()
    {
        if (mRootVisual == null && Application.Current != null)
        {
            mRootVisual = Application.Current.RootVisual as FrameworkElement;
        }
    }
 
    #region Attached Property
 
    public static readonly DependencyProperty ContextMenuProperty =
        DependencyProperty.RegisterAttached("ContextMenu", typeof(ContextMenu), typeof(RightClickService), null);
 
    public static void SetContextMenu(UIElement element, ContextMenu value)
    {
        element.SetValue(ContextMenuProperty, value);
    }
    public static ContextMenu GetContextMenu(UIElement element)
    {
        return (ContextMenu)element.GetValue(ContextMenuProperty);
    }
 
    #endregion
 
    static RightClickService()
    {
        if (Application.Current.Host.Settings.Windowless == false) throw new Exception("Your SL plugin must be initialize with Windowless to true");
 
        if (HtmlPage.IsEnabled) HtmlPage.Document.AttachEvent("oncontextmenu", RightClickService.OnContextMenu);
    }
 
    private static void OnContextMenu(object sender, HtmlEventArgs e)
    {
        IEnumerable<UIElement> elements = GetControls(e.OffsetX, e.OffsetY);
 
        if (elements != null)
        {
            foreach (UIElement element in elements)
            {
                ContextMenu menu = RightClickService.GetContextMenu(element);
 
                if (menu != null)
                {
                    PerformPlacement(menu, e.OffsetX, e.OffsetY);
                    break;
                }
            }
        }
 
        e.PreventDefault();
    }
 
    internal static Popup Popup { get; set; }
 
    private static void PerformPlacement(FrameworkElement content, int x, int y)
    {
        Canvas elementOutside = new Canvas();
        Canvas childCanvas = new Canvas();
 
        elementOutside.Background = new SolidColorBrush(Colors.Transparent);
 
        if (Popup != null)
        {
            Popup.IsOpen = false;
            if (Popup.Child is Canvas) ((Canvas)Popup.Child).Children.Clear();
        }
        Popup = new Popup();
 
        Popup.Child = childCanvas;
 
        elementOutside.MouseLeftButtonDown += new MouseButtonEventHandler((o, e) => Popup.IsOpen = false);
        elementOutside.Width = Application.Current.Host.Content.ActualWidth;
        elementOutside.Height = Application.Current.Host.Content.ActualHeight;
 
        childCanvas.Children.Add(elementOutside);
        childCanvas.Children.Add(content);
 
        Canvas.SetLeft(content, x);
        Canvas.SetTop(content, y);
 
        Popup.IsOpen = true;
    }
 
    private static IEnumerable<UIElement> GetControls(int x, int y)
    {
        return VisualTreeHelper.FindElementsInHostCoordinates(new Point(x, y), RootVisual);
    }
}

Il suffit simplement passer par l’évènement Javascript oncontextmenu.

Afin de spécifier le menu contextuel de chaque contrôle je passe par une attached property. Lorsque le clic droit est détecté je récupère tout d’abord le contrôle en utilisant les coordonnée de la souris et le VisualTreeHelper, puis le menu associé au contrôle. J’affiche ensuite le menu dans un Popup.

Petite astuce : j’utilise un canvas invisible faisant toute la taille de l’application permettant de fermer le menu lorsque l’utilisateur clique en dehors de celui-ci.

C’est terminé pour le contrôle.

L’utilisation est assez simple.

<UserControl x:Class="TestSilverlight.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cm="clr-namespace:ContextMenu;assembly=ContextMenu"
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <Image Source="silverlight.png">
            <cm:RightClickService.ContextMenu>
                <cm:ContextMenu>
                    <cm:ContextMenuItem Content="Save As" Click="SaveImage" />
                    <cm:ContextMenuItem Content="View Image" Click="ViewImage" />
                </cm:ContextMenu>
            </cm:RightClickService.ContextMenu>
        </Image>
    </Grid>
</UserControl>

Je rappelle juste que ce code ne fonctionne pas extrêmement bien sous Firefox.

Voici le lien pour les sources.

Have fun :)

[Silverlight] Une image affichant sa progression

silverlight Bonjour à tous,

J’avoue le titre n’est peut-être pas très explicite, mais dans ce post nous allons voir comment créer une image affichant le fameux sablier du post précédent tant que cette dernière n’est pas chargée.

On crée tout d’abord notre XAML composé en tout et pour tout de deux contrôles : une Image et un Loading.

<UserControl x:Class="Sky.Controls.ImageProgress"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Sky.Controls">
    <Grid x:Name="LayoutRoot" Background="White">
        <Image x:Name="Image" Stretch="Fill" />
        <local:Loading x:Name="Buffer" />
    </Grid>
</UserControl>

Tout le reste va être réalisé en C#.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
 
namespace Sky.Controls
{
    public partial class ImageProgress : UserControl
    {
        public ImageProgress()
        {
            InitializeComponent();
        }
 
        public BitmapImage Source
        {
            get { return (BitmapImage)GetValue(SourceProperty); }
            set
            {
                SetValue(SourceProperty, value);
                value.DownloadProgress += new EventHandler<DownloadProgressEventArgs>(value_DownloadProgress);
                this.Image.Source = value;
                this.BeginAnimation();
            }
        }
 
        void value_DownloadProgress(object sender, DownloadProgressEventArgs e)
        {
            if (e.Progress == 100)
            {
                StopAnimation();
            }
        }
 
        // Using a DependencyProperty as the backing store for Source.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SourceProperty =
            DependencyProperty.Register("Source", typeof(BitmapImage), typeof(ImageProgress), new PropertyMetadata(new PropertyChangedCallback(OnSourceChanged)));
 
        private static void OnSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ImageProgress source = sender as ImageProgress;
            if (source != null) source.Source = (BitmapImage)e.NewValue;
        }
 
        private void BeginAnimation()
        {
            this.Buffer.Start();
        }
 
        private void StopAnimation()
        {
            this.Buffer.Stop();
            this.Buffer.Visibility = Visibility.Collapsed;
        }
    }
}

Rien de bien compliqué. Tout d’abord on crée une DP pour la Source de notre Image. Lorsque cette DP est modifiée on lance le téléchargement de notre image et on affiche notre sablier. Lorsque le téléchargement est terminé, on le cache, tout simplement.

Ce petit contrôle s’avère très utile dans des applications affichant un certains nombres d’images venant de sources extérieures.

On pourrait également checker l’evènement ImageFailed du contrôle Image afin d’afficher une image d’erreur si la source n’est pas disponible.

Have fun !

[Silverlight] Un contrôle type sablier

silverlight Bonjour à tous,

Aujourd’hui je vais vous présenter un contrôle assez pratique, puisqu’il s’agit d’un contrôle type sablier sous Windows Vista. Ce contrôle permet de signifier à l’utilisateur qu’une action est en train de se passer.

 loading

Le code pour réaliser ce contrôle est assez simple. Une ellipse à laquelle on anime le GradientBrush de son Stroke.

<UserControl x:Class="Sky.Controls.Loading"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <UserControl.Resources>
        <Storyboard x:Name="Animation" RepeatBehavior="Forever">
            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(Shape.Stroke).(LinearGradientBrush.StartPoint)">
                <SplinePointKeyFrame KeyTime="00:00:00.2500000" Value="0.846,0.139"/>
                <SplinePointKeyFrame KeyTime="00:00:00.5000000" Value="1,0.491"/>
                <SplinePointKeyFrame KeyTime="00:00:00.7500000" Value="0.869,0.838"/>
                <SplinePointKeyFrame KeyTime="00:00:01" Value="0.494,1"/>
                <SplinePointKeyFrame KeyTime="00:00:01.2500000" Value="0.167,0.873"/>
                <SplinePointKeyFrame KeyTime="00:00:01.5000000" Value="0,0.494"/>
                <SplinePointKeyFrame KeyTime="00:00:01.7500000" Value="0.146,0.146"/>
                <SplinePointKeyFrame KeyTime="00:00:02" Value="0.494,-0.001"/>
            </PointAnimationUsingKeyFrames>
            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(Shape.Stroke).(LinearGradientBrush.EndPoint)">
                <SplinePointKeyFrame KeyTime="00:00:00.2500000" Value="0.154,0.861"/>
                <SplinePointKeyFrame KeyTime="00:00:00.5000000" Value="0,0.509"/>
                <SplinePointKeyFrame KeyTime="00:00:00.7500000" Value="0.131,0.162"/>
                <SplinePointKeyFrame KeyTime="00:00:01" Value="0.506,0"/>
                <SplinePointKeyFrame KeyTime="00:00:01.2500000" Value="0.833,0.127"/>
                <SplinePointKeyFrame KeyTime="00:00:01.5000000" Value="1,0.506"/>
                <SplinePointKeyFrame KeyTime="00:00:01.7500000" Value="0.854,0.854"/>
                <SplinePointKeyFrame KeyTime="00:00:02" Value="0.506,1.001"/>
            </PointAnimationUsingKeyFrames>
        </Storyboard>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Ellipse Width="25" Height="25" StrokeThickness="5.5" x:Name="ellipse">
            <Ellipse.Stroke>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FF096475" Offset="0.571"/>
                    <GradientStop Color="#FFA8FCFC" Offset="1"/>
                </LinearGradientBrush>
            </Ellipse.Stroke>
        </Ellipse>
    </Grid>
</UserControl>

Finalement une pointe de C#, pour lancer et arrêter l’animation.

public void Start()
{
    this.Animation.Begin();
}
 
public void Stop()
{
    this.Animation.Stop();
}

Le résultat est assez agréable à voir. Libre à vous de changer les couleurs.

Have fun !

[ASP.NET MVC] Traduction des 38 tutoriels officiels

L’équipe .NET de Developpez.com, dont je fais partie, vient de traduire les 38 tutoriels officiels sur ASP.NET MVC.

Au programme :

  • Présentation d'ASP.NET MVC
  • Le routing
  • Les Contrôleurs
  • Les Vues
  • Les Modèles
  • La validation
  • Master Pages
  • Les filtres d'actions
  • Améliorer les performances avec le caching
  • Sécurité
  • Testing
  • Navigation
  • Le déploiement
  • Développement d’une application de gestion de contacts avec ASP.NET MVC

38 tutoriels pour maîtriser ASP.NET MVC

Nous préparons également la traduction des quelques 46 tutoriels sur ASP.NET AJAX.

Bonne lecture !

[Silverlight] Votez pour mon jeu

Bonjour tout le monde.

Aujourd’hui pas d’astuces ou de news sur Silverlight, mais simplement une petite demande d’entraide.

Je participe à un concours sur le développement d’un jeu en Silverlight, j’ai donc réalisé le mien qui se trouve dans les 16 finalistes. Le reste des votes est fait par les visiteurs.

J’écris donc ce post afin de demander à tout le monde de voter pour moi, dans la mesure où mon jeu vous plait bien évidemment. Comme dit dans la description, je n’ai strictement aucun talent des graphiste, mon jeu est donc assez basique à ce niveau là.

Pour voter pour moi, il suffit simplement de se rendre sur cette page http://www.serverquestcontest.com/register.aspx afin de s’enregistrer (les informations, adresses mails ne sont pas vérifiées) puis d’aller sur cette page http://www.serverquestcontest.com/game.aspx?GID=30 afin de tester et de voter pour mon jeu.

Je remercie toutes les personnes qui prendront quelques minutes de leur temps pour moi :)

Annonce de Silverlight 3

C’est aujourd’hui au Mix 09, qui se déroule à Las Vegas, que vient d’être annoncé la première beta de Silverlight 3.

Il ne s’agit pas d’un changement technologique comme il avait été question entre Silverlight 1 et Silverlight 2, mais l’ajout de nouvelles fonctionnalités toutes plus cool les unes que les autres.

Application hors-navigateur

  • Silverlight 3 vous autorise à créer des applications pouvant s’exécuter hors de votre navigateur. Vous n’êtes donc plus obliger de posséder une connexion Internet pour lancer votre application. Des raccourcis sont également disposés sur le bureau.

Amélioration des graphismes

  • Silverlight 3 supporte l’accéleration pour la GPU. Ceci vous autorise donc à utiliser des Pixel Shaders. Quelques effets sont déjà présents tel que le Blur ou le Drop Shadow. Libre à vous de créer les vôtres (à conditions de connaitre le HLSL). La version 3 permet également de donner une impression de 3D en utilisant des perspectives, elle donne également accès à une nouvelle API de création de Bitmap.

Amélioration des contrôles

  • Le nouveau système de contrôle permet de réaliser une validation sur ces derniers (à l’instar de la validation en ASP.NET). De nouveaux contrôles font également leur apparition comme la ListBox multisélection, ainsi que la SaveFileDialog, permettant à l’utilisateur d’enregistrer un fichier sur sa machine.

Style

  • Le nouveau système de style, permet de pouvoir changer celui de votre application au runtime (peut-être le même système que dans le Toolkit…).

Media

  • Support de nouveaux formats tels que le H264 (HD). Vous pouvez également construire vos propres codecs si vous voulez utiliser un format non supporté.

Amélioration des performances

Plusieurs améliorations du côtés de performances sont à noter :

  • Les Font peuvent maintenant être zippés pour réduire la taille du téléchargement
  • Silverlight 3 peut utiliser les fonts de l’OS
  • DeepZoom est capable d’afficher pres de 1000 éléments
  • Le XML binarisé est maintenant supporté pour améliorer la communication serveur/application
  • Votre application peut maintenant convertir une partie de votre arbre de rendu en un Bitmap pour accélérer l’affichage.

 

Vous pouvez donc maintenant télécharger Silverlight 3 pour voir les nouveautés décrites plus haut, mais celles aussi que je n’ai pas citées.

Une dernière chose : Silverlight 2 et Silverlight 3 ne cohabitent pas ensemble. Il vous faudra donc installer SL3 sur une autre machine (virtuelle par exemple) afin de pouvoir développer avec.

Silverlight 3 n’est de plus pas disponible sous license Go-live, les applications ne peuvent donc pas êtres publiées.

On se retrouve bientôt pour les nouveautés en images !

[Silverlight] Astuce du jour #08 - Appeler du code-behind C# depuis du Javascript

Bonjour à tous,

Dans cette nouvelle astuce nous allons voir comment appeler du code-behind C# depuis une fonction javascript.

Nous allons tout d'abord ajouter l'attribut [ScriptableType] à notre classe.

[ScriptableType] 
public partial class Page : UserControl 
{ 
    [...] 
}

Nous allons ensuite créer la méthode qui va être appelée depuis le Javascript.

[ScriptableMember] 
public string HelloFromSilverlight(string name) 
{ 
    return string.Format("Hello From Silverlight {0}", name); 
}

On n'oublie pas l'attribut ScriptableMember, et la visibilité de notre méthode à public.

Nous allons maintenant enregistrer notre objet.

HtmlPage.RegisterScriptableObject("SLapp", this);

C'est tout pour le côté C#.

Passons maintenant côté JS :

<script language="javascript" type="text/javascript">
   1:  
   2:     function HelloFromJS() { 
   3:         var sl = document.getElementById("Xaml1"); 
   4:         if (sl != null) { 
   5:             var hello = sl.Content.SLapp.HelloFromSilverlight("Sky"); 
   6:             alert(hello); 
   7:         } 
   8:     } 
</script>
 
[...]
 
<asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/TestSilverlight.xap" MinimumVersion="2.0.30523" Width="100%" Height="100%" />

On récupère notre contrôle Silverlight via la méthode getElementById puis on appelle notre méthode. On veille à bien nommer notre objet avec la nom qu'on a utilisé dans la méthode RegisterScriptableObject (ici SLapp).

Ici l'exemple est assez inutile, mais vous connaissez maintenant le principe, si un jour vous êtes confrontés à cette problématique.

A bientôt.

[Silverlight] Astuce du jour #07 - La boite de dialogue OpenFileDialog

Silverlight 2 nous permet de sélectionner un fichier sur le poste client, via la boite de dialogue OpenFileDialog.

Cette dernière nous permet d'obtenir entre autre un Stream sur le fichier sélectionné par l'utilisateur, afin de le lire ou de l'uploader sur un serveur.

Comment faire ?

OpenFileDialog openFile = new OpenFileDialog(); 
openFile.Multiselect = false; 
openFile.Filter = "Images files (*.jpg,*.png)|*.jpg;*.png"; 
 
if (openFile.ShowDialog() == true) 
{ 
    Stream stream = openFile.SelectedFile.OpenRead(); 
 
    using (StreamReader reader = new StreamReader(stream)) 
    { 
        // What you want ! 
    } 
}

On remarque tout d'abord la propriété Multiselect qui nous permet de sélectionner ou pas plusieurs fichiers.

Ensuite la propriété Filter qui nous permet d'appliquer un filtre sur le type de fichier sélectionnable par l'utilisateur. Ici on réduit la sélection aux fichier images jpg et png.

Pour récupérer le fichier sélectionné par l'utilisateur on se sert de la propriété SelectedFile qui nous retourne un objet de type FileDialogFileInfo.

Cet objet contient une méthode OpenRead retournant un Reader sur le fichier. Il contient également une propriété Name retournant le nom du fichier et une méthode OpenText (utile pour les fichiers texte).

On se sert ensuite du Reader obtenu pour créer un StreamReader afin de lire notre fichier.

Remarque : Dans le cas d'une sélection multiple, il faut utiliser la propriété SelectedFiles qui retourne un IEnumerable<FileDialogFileInfo>.

C'est tout pour l'utilisation de la boite de dialogue OpenFileDialog en Silverlight 2.

A bientôt pour une nouvelle astuce sur Silverlight.

[Silverlight] Astuce du jour #06 – Utiliser les paramètres d'initialisation

Il existe 2 façons d'initialiser son application avec des paramètres :

  • des paramètres dans l'URL du type TestPage.html?param1=val1&param2=val2
  • des paramètres dans la page contenant votre contrôle

Pour récupérer les paramètre dans l'URL il suffit simplement de récupérer la QueryString de cette façon :

string param1 = HtmlPage.Document.QueryString["param1"]; 
string param2 = HtmlPage.Document.QueryString["param2"];

Pour récupérer les paramètres dans une page, il faut tout d'abord les ajouter :

Pour une page aspx utilisant un contrôle <asp:Silverlight>, il faut utiliser la propriété InitParameters.

<asp:Silverlight ID="Xaml1" runat="server" InitParameters="param1=val1,param2=val2" ... />

Pour une page html utilisant une balise <object>, il faut utiliser le paramètre <param> avec comme nom initParams.

<object data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%"> 
    <param name="source" value="ClientBin/TestSilverlight.xap"/> 
    <param name="onerror" value="onSilverlightError" /> 
    <param name="background" value="white" /> 
    <param name="initParams" value="param1=val1,param2=val2" /> 
    ... 
</object>

On veille bien à séparer nos paramètres par des virgules.

Pour récupérer ces paramètres, il faut se rendre dans la méthode Application_Startup du fichier App.xaml.cs.

private void Application_Startup(object sender, StartupEventArgs e) 
{ 
    if (e.InitParams.Count == 0) this.RootVisual = new Page(); 
    else this.RootVisual = new Page(e.InitParams); 
}

On récupère nos paramètres via la propritété InitParams.

Dans mon exemple, il suffit donc de créer un nouveau constructeur recevant en paramètre un IDictionnary<string,string>.

C’est tout pour cette astuce Silverlight.

[Silverlight] Astuce du jour #05 - DeepZoom et Silverlight : How To

silverlight Dans cette nouvelle astuce, nous allons voir comment créer une collection de photos DeepZoom et comment l'intégrer dans un projet Silverlight.

Tout d'abord, il nous faut télécharger DeepZoom : http://www.microsoft.com/downloads/details.aspx?FamilyID=457b17b7-52bf-4bda-87a3-fa8a4673f8bf&DisplayLang=en

Une fois l'installation terminée, on le lance.

 deep1

On crée un nouveau projet :

 deep2

On rajoute les images que l'on veut voir apparaitre dans notre collection, en cliquant sur Add Images

 deep3

On passe ensuite dans l'onglet Compose pour positionner nos images.

deep4

On passe maintenant sur le dernier onglet, c'est à dire Export

deep5

On choisit un export en Silverlight (il y a possibilité de publier sa collection sur PhotoZoom si vous possédez un compte), et on donne un nom à son projet. Et on clic sur Export.

deep6

DeepZoom se chargera de créer la solution Visual Studio et tout le code nécessaire.

Une fois l'export effectué, on a le choix entre plusieurs actions, comme voir le résultat dans la navigateur, ouvrir le repertoire contenant la solution...

deep7

Voici le résultat pour ma collection

deep8

A noter que le projet créé contient la classe MouseWheelHelper pour nous permettre de zoomer et dézoomer via la molette. On peut également se déplacer dans la collection via la souris.

Le procédé est donc comme vous pouvez le voir, simplissime, nous n'avons pas écrit une seule ligne de code.

[Silverlight] Astuce du jour #04 - Augmenter la taille de l'Isolated Storage

Dans mon précédent billet, je vous expliquais comment utiliser l'Isolated Storage en Silverlight 2.

Dans cette nouvelle astuce nous allons voir, comment augmenter sa taille, qui je le rappelle, est limitée par défaut à 1Mo.

Voici donc une méthode à rajouter dans la classe IsolatedStorageHelper.

public static bool ExtendQuota(long sizeInBytes) 
{ 
    using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication()) 
    { 
        if (sizeInBytes < storage.Quota) return false; 
        return storage.IncreaseQuotaTo(sizeInBytes); 
    } 
}

On peut également récupérer la taille et l'espace restant via les propriétés Quota et AvailableFreeSpace.

Remarque : Tout comme le passage en Fullscreen d'une application, la demande d'augmentation du quota ne peut se faire qu'à la demande de l'utilisateur, c'est-à-dire dans un évènement où ce dernier est mis en scène (clic de souris sur un bouton par exemple).

Un pop-up de confirmation apparaitra pour que l'utilisateur confirme ou pas l'extension de quota.

isolated

Le quota accordée à une application reste visible dans la fenêtre de configuration de Silverlight, onglet Application Storage.

isolated2

Voici donc tout ce que vous devez savoir sur l'Isolated Storage en Silverlight 2.

[Silverlight] Astuce du jour #03 - Utiliser l'Isolated Storage

silverlight Dans cette nouvelle astuce nous allons voir comment utliser l'IsolatedStorage en Silverlight.

L'Isolated Storage est un système de fichier virtuel mis à notre disposition pour stocker les données de nos applications Silverlight. Sa taille initiale est de 1Mo.

Voici une classe pour utiliser l'Isolated Storage en Silverlight 2 (tout n'est pas présent).

public static class IsolatedStorageHelper 
{ 
    public static void CreateDirectory(string path) 
    { 
        using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication()) 
        { 
            if (storage.DirectoryExists(path) == false) storage.CreateDirectory(path); 
        } 
    } 
 
    public static void DeleteDirectory(string path) 
    { 
        using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication()) 
        { 
            if (storage.DirectoryExists(path) == true) storage.DeleteDirectory(path); 
            else throw new DirectoryNotFoundException(path); 
        } 
    } 
 
    public static string[] ListDirectories(string pattern) 
    { 
        using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication()) 
        { 
            if (pattern != null) return storage.GetDirectoryNames(pattern); 
            else return storage.GetDirectoryNames(); 
        } 
    } 
 
    public static string[] ListFiles(string pattern) 
    { 
        using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication()) 
        { 
            if (pattern != null) return storage.GetFileNames(pattern); 
            else return storage.GetFileNames(); 
        } 
    } 
 
    public static void SaveData(string path, string data) 
    { 
        using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication()) 
        { 
            using (StreamWriter sw = new StreamWriter(storage.OpenFile(path, FileMode.Append, FileAccess.Write))) 
            { 
                sw.Write(data); 
                sw.Close(); 
            } 
        } 
    } 
 
    public static string LoadData(string path) 
    { 
        using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication()) 
        { 
            if (storage.FileExists(path)) 
            { 
                using (StreamReader sw = new StreamReader(storage.OpenFile(path, FileMode.Open, FileAccess.Read))) 
                { 
                    return sw.ReadToEnd(); 
                } 
            } 
            else throw new FileNotFoundException(path); 
        } 
    } 
 
    public static void DeleteFile(string path) 
    { 
        using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication()) 
        { 
            if (storage.FileExists(path)) storage.DeleteFile(path); 
            else throw new FileNotFoundException(path); 
        } 
    } 
}
 

Avant chaque action on récupère notre Isolated Storage

IsolatedStorageFile.GetUserStoreForApplication()

Et ensuite on peut travailler dessus (créer des fichiers, des répertoires, les supprimer, les lister, écrire dedans...).

Remarque : On peut visualiser les différentes applications qui utilisent l'Isolated Storage en faisant un clic droit sur un contrôle Silverlight, puis Silverlight Configuration et enfin dans l'onglet Application Storage.

isolated

A noter qu'on peut désactiver l'Isolated Storage en décochant la case.

C’est terminé pour cette astuce.

[Silverlight] Astuce du jour #02 - Mettre son application en Fullscreen

silverlight Dans cette nouvelle astuce nous allons voir comment mettre son application en fullscreen (plein écran) en Silverlight 2.

Pour cela une simple ligne de code suffit

Application.Current.Host.Content.IsFullScreen = true/false;

Il y a seulement un petit problème, notre application a exactement la même taille qu'en mode normal (pour une application avec une taille fixe), il faut donc la redimensionner.

Pour cela nous allons tout d'abord ajouter une transformation de type ScaleTransform à notre Grid principal.

<Grid.RenderTransform> 
    <ScaleTransform x:Name="LayoutRootScaleTransform" /> 
</Grid.RenderTransform>

On ajoute ensuite des membres à notre classe pour stocker la taille initiale de notre application.

double mInitialWidth = 0; 
double mInitialHeight = 0; 
 
public Page() 
{ 
    InitializeComponent(); 
 
    mInitialWidth = this.Width; 
    mInitialHeight = this.Height; 
    [...] 
}

On s'abonne ensuite à l'évènement FullScreenChanged.

Application.Current.Host.Content.FullScreenChanged += new EventHandler(Content_FullScreenChanged);

Et dans la callback on effectue notre transformation.

void Content_FullScreenChanged(object sender, EventArgs e) 
{ 
    double currentWidth = Application.Current.Host.Content.ActualWidth; 
    double currentHeight = Application.Current.Host.Content.ActualWidth; 
 
    double minRatio = Math.Min((currentWidth / mInitialWidth), (currentHeight / mInitialHeight)); 
 
    LayoutRootScaleTransform.ScaleX = LayoutRootScaleTransform.ScaleY = minRatio; 
}

On n'oublie pas de faire en sorte que notre application garde le même ratio en taille (Math.Min) et on applique la transformation.

Remarque : On ne peut pas mettre son application en fullscreen à son instantiation (à l'évènement Loaded par exemple), en effet la mise en plein écran d'une application doit être la volonté de l'utilisateur, de ce fait cela ne fonctionne que dans des évènements mettant en scène ce dernier (clavier [KeyDown...], souris [MouseLeftButtonDown, Click...]).

Contraintes : Une fois l'application en fullscreen, les fonctionnalités du clavier sont réduites, on ne peut capter que les touches directionnelles (flèches), et la barre d'espace.

C'est fini pour cette nouvelle astuce consacrée à Silverlight 2.

[Silverlight] Astuce du jour #01 – Comment « progresser » le téléchargement d’une image externe

silverlight Bienvenue à tous pour ma première astuce du jour, idée inspirée par les posts du même nom (en anglais) sur le blog de Mike Snows.

Pour cette première astuce nous allons voir comment « progresser » le téléchargement d’une image externe en Silverlight 2 (si vous connaissez un meilleur mot que « progresser » ce serait cool :)

Très pratique pour afficher un message d'attente lors du téléchargement de l'image. Je posterai d’ailleurs bientôt un UserControl affichant une barre de chargement tant que l’image n’est pas chargée.

void Page_Loaded(object sender, RoutedEventArgs e)
{
    BitmapImage bImage = new BitmapImage();
    bImage.DownloadProgress += new EventHandler<DownloadProgressEventArgs>(image_DownloadProgress);
    bImage.UriSource = new Uri("http://farm4.static.flickr.com/3021/2613657604_30d8f2e7aa_o.jpg", UriKind.Absolute);
    this.image.Source = bImage;
}
 
 
void image_DownloadProgress(object sender, DownloadProgressEventArgs e)
{
    if (e.Progress == 100)
    {
        // download finished
    }
}

Une autre solution consiste à utiliser la classe WebClient.

void Page_Loaded(object sender, RoutedEventArgs e)
{
    WebClient client = new WebClient();
    client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
    client.OpenReadAsync(new Uri("http://farm4.static.flickr.com/3021/2613657604_30d8f2e7aa_o.jpg", UriKind.Absolute));
}
 
void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    if (e.Error == null)
    {
        BitmapImage bimage = new BitmapImage();
        bimage.SetSource(e.Result);
        this.image.Source = bimage;
    }
}
 

A noter que le serveur distant doit autoriser les opérations cross-domain (c'est le cas pour Flickr).

A bientôt pour une prochaine astuce.

One more !

Bonjour à tous.

Voici donc un nouveau venu sur les célèbres blogs de CS.

Je vais tout d’abord me présenter rapidement.

Je m’appelle Benjamin Roux, j’ai 22 ans et je suis actuellement en dernière année à SUPINFO où je suis également formateur .NET. Je termine ma dernière année à San Francisco où je prépare également un IT Management & Marketing Certificate en partenariat avec la Dominican University Of California.

Côté professionnel, j’ai été nommé MVP Client Application Development pour mon expertise en Silverlight, qui sera le sujet principal de ce blog. Je traine également sur Developpez.com où est hébergé mon site web ainsi que mon ancien blog (duquel je vais tenter de ramener quelques posts). Vous me trouverez la plupart du temps sur les forums .NET et en particulier sur le forum Silverlight.

Comme je l’ai déjà dit, le sujet principal de ce blog sera donc Silverlight (news, astuces, codes, articles…) mais aussi .NET, Windows et Microsoft en général.

Pour terminer, je vais remercier Thomas qui m’a dirigé sur Cyril pour l’ouverture de ce blog.

A bientôt !

Plus de Messages « Page précédente


Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01