Benjamin Roux

Silverlight Expert - Silverlight Fan - MVP Client App Dev
[Silverlight] Need Silverlight graphist for an online game

Hi everyone,

I just created a multiplayer turn-based online game and I'm looking for a Silverlight graphist to realize the design of the game itself and of the hosting website (room, room chat, in-game chat...).

The game is 90% completed but I cant publish it as is, I need a good graphist for making it awesome!

In case of success and if we make some money, there will be equal share!

Just post a comment or contact me if you’re interested.

The Memoirs of Sir Isaac Newton's life in Silverlight

The Royal Society just published a manuscript of William Stukeley which relates the life of Sir Isaac Newton with, of course, the famous apple which leads to the general gravitational low.

This manuscript, as well as many others, are available for consultation through a Silverlight player but also a xbap version.

[Silverlight] My Entry for the MIX 10K Coding Challenge

Hello everyone,

Today, I’d like to present you my entry for the MIX 10K Coding Challenge.

http://mix10k.visitmix.com/Uploads/140/Thumbnail.jpg

For those who don’t know this challenge, the rules are really simple. You have to submit an application whose the source code’s size is less than 10 kilobytes. The technologies allowed are Silverlight, HTML5 and Gestalt.

As you can guess, I chose Silverlight 3 and my source code’s size is 9.5 kilobytes.

So if you like my app, vote for me!

http://mix10k.visitmix.com/Entry/Details/140

Thanks!

[Silverlight] An image loading control

Re,

Ok the title is not really explicit but in this post we’re going to see an image control which display the busy pointer that we saw in my previous post, until the image be loaded.

First we create the Xaml composed with two controls: an image and the Busy pointer.

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

And some C#

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
 
namespace xxx
{
    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.IsBusy = true;
        }
 
        private void StopAnimation()
        {
            this.Buffer.IsBusy = false;
            this.Buffer.Visibility = Visibility.Collapsed;
        }
    }
}

I created a Dependency Property for the image’s source. When this DP is changed, I download the image from the source we I display the busy pointer. When the download is complete I stop the animation and hide it.

This control can be really useful if your application uses images from external source like Flickr or Bing.

We could check the ImageFailed event for notifying the user if there is an error.

Live sample: http://broux.developpez.com/public/SL/ImageProgress/index.html (the image is 4MB).

[Silverlight] A busy mouse pointer

Hello everyone,

Today I’m gonna present you a control which can be really useful, since you can find him in Windows: the busy mouse pointer. This control is used for notice the user than something is happening.

loading

 

The code for this control is quite simple.

#region Dependency Properties
 
public bool IsBusy
{
    get { return (bool)GetValue(IsBusyProperty); }
    set 
    { 
        SetValue(IsBusyProperty, value);
        ChangeState();
    }
}
 
// Using a DependencyProperty as the backing store for IsBusy.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsBusyProperty =
    DependencyProperty.Register("IsBusy", typeof(bool), typeof(BusyPointer), new PropertyMetadata(new PropertyChangedCallback(OnBusyChanged)));
 
private static void OnBusyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    ((BusyPointer)sender).IsBusy = (bool)e.NewValue;
}
 
#endregion
 
#region Initialization
 
public BusyPointer()
{
    this.DefaultStyleKey = typeof(BusyPointer);
}
 
#endregion
 
#region Methods
 
private void ChangeState()
{
    if (IsBusy) VisualStateManager.GoToState(this, "Busied", true);
    else VisualStateManager.GoToState(this, "Normal", true);
}
 
#endregion

Juste a very simple control with a IsBusy property. When the value is true the animation starts, when it’s false it stops.

And the theme I use.

<Style TargetType="local:BusyPointer">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:BusyPointer">
                <Grid x:Name="LayoutRoot" Background="Transparent">
                    <vsm:VisualStateManager.VisualStateGroups>
                        <vsm:VisualStateGroup x:Name="CommonStates">
                            <vsm:VisualState x:Name="Normal" />
                            <vsm:VisualState x:Name="Busied">
                                <Storyboard>
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetName="VisualElement" Storyboard.TargetProperty="(UIElement.RenderTransform).Angle" RepeatBehavior="Forever">
                                        <SplineDoubleKeyFrame KeyTime="0:0:1" Value="360" />
                                    </DoubleAnimationUsingKeyFrames>
                                </Storyboard>
                            </vsm:VisualState>
                        </vsm:VisualStateGroup>
                    </vsm:VisualStateManager.VisualStateGroups>
                    <Ellipse Width="25" Height="25" StrokeThickness="5.5" x:Name="VisualElement">
                        <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.RenderTransform>
                            <RotateTransform CenterX="12.5" CenterY="12.5" />
                        </Ellipse.RenderTransform>
                    </Ellipse>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

You can change the colors, the animation, the shape, everything!

Have fun!

[Silverlight] How to handle the contextual menu

silverlight_thumb5 Hello again,

There is a question that I often see on Silverlight’s forum. It’s about the contextual menu (right click). The current answer is that it’s not possible to surcharge them like we can do in Flash. Maybe in the next version of Silverlight…

However I’m gonna show you a solution I created for bypass the classic right click. Unfortunatly my method works well on Internet Explorer and quite bad on Firefox where the classic menu displays and then the custom menu. If someone knows a workaround for Firefox he can post a comment.

For an easy use I created a RightClickService class, which allow us to create contextual menus for a lot of controls.

First, the code for ContextMenuItem and 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);
    }
}

It’s just a simple control who looks like a ListBoxItem. I also created a Click event which is fired when a MouseLeftButtonDown occurs.

The theme’s control:

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

 

The 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);
    }
}

This control inherits from ItemsControl, and overrides the GetContainerForItemOverride and IsItemItsOwnContainerOverride methods for define the control to use for the display if we don’t use a ContextMenuItem.

And now the big part: 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);
    }
}

I just use the oncontextmenu Javascript event.

For specify the contextual menu for a control I use an attached property. When the right click is detected I get the control by using the coordinate of the mouse and the VisualTreeHelper class, then the menu associated to the control. Then I display the menu in a Popup.

Trick: I use an invisible Canvas which fill the entire application. It allows to close the menu when the user clicks outside it.

It’s over for the control, now let’s see how to use it.

First there is one requirement: your Silverlight plugin must be initialize with the Windowless property to true.

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

You see? It’s simple.

And the result:

screen

Have fun :)

A new one

Hello everybody and welcome to my English weblog.

Just a few words about me.

My name is Benjamin Roux and I just finished my studies in a French private school where I was also .NET trainer. The last 2 years I gave courses in France, USA and China and that’s the reason why I lived  in San Francisco (which is the most cool, beautiful, awesome city I’ve ever seen…) from October to July.

Microsoft awarded me with the title of Client Application Development MVP for my contributions in the French community. By the way, for the French readers you can find my weblog here http://blogs.developpeur.org/broux/ and my articles here http://broux.developpez.com/.

I opened this blog to share my experience and my researches about the .NET technologies and specially Silverlight which is my favourite. I hope my posts will be helpful!

As you could guess, English is not my mother tongue so in advance, all my apologies for my mistakes.

See you in my next post.

Posted: Aug 20 2009, 08:23 AM by Benjamin Roux | with no comments
Filed under:
More Posts