Ed Silverton

Category: Silverlight

Silverlight for Flash Developers talk

As promised here’s all the gubbins related to the talk/occult ritual last night:

www.unwrong.com/download/Silverlight_for_Flash_Developers.zip

The .zip contains the Powerpoint slides, HelloUnderworld Visual Studio Project and OuijaBoard Visual Studio Project.

All the links I referred to should be in the Powerpoint slides, but if there’s anything missing feel free to ask me for it!

We’ve uploaded some photos to the Unwrong Flickr profile.

3D Flickr Explorer by you.

We’ve also uploaded the Ouija Board finale to the Unwrong Vimeo profile!

P.s, thank you to Richard Willis (@richtextformat) for inspiring the night’s occult theme with his imaginative FlashBrighton billing!

Pps, there seems to be a problem with wordpress.com where it’s not letting me enable comments :-( If you’d like to comment you can reach me here: http://twitter.com/edsilv

Source for 3D Flickr Photo Explorer

I’ve just completed updating my 3D Flickr Photo Explorer for Silverlight 2 RTW. Here’s the Visual Studio solution if you fancy seeing how it works:

http://cid-5f8a4662a2d170e4.skydrive.live.com/self.aspx/Blog/PhotoExplorer3D.zip

I couldn’t include the Helvetica font I used for obvious licensing/redistribution reasons.

It’s worth noting too which open source libraries I’m using:

agTweener
FlickrNet
Kit3D
Tweener (of T)

You may be wondering why I used two different tweening libraries. Tweener (of T) is much better (in this context) at handling the zooming in/out effect than agTweener. If I were to hazard a guess why I’d say it’s because Tweener (of T) uses DispatcherTimer to animate instead of StoryBoards. The UI thread is already having to cope with drawing a full screen of photos flying about, so it makes sense to use another thread to calculate their positions. I’ve heard that using DispatcherTimer for tweening isn’t as visually smooth as StoryBoards, but it looks ok to me. I’m using agTweener to handle all other fading effects because that was what I started out with and couldn’t see any point in porting all other tween effects to Tweener (of T).

Silverlight 3D Flickr Photo Explorer

I’ve been working on a pet project to see what I can do in 3D with Silverlight. The idea was to allow the user to enter a search phrase to query a source like Flickr, then display the resulting photos scattered about in a 3D scene where the user can zoom in/out. Here it is in its current form.

Type in a query then hit Enter (or Return) to get a set of photos. Click on photos to view them full-size then click on the background (or mousewheel) to zoom out again.

One thing I like about it is that the search field never loses focus. I also rather like the haphazard arrangements of images as opposed to the boring grids you normally get.

I used Kit3D for the 3D engine and FlickrNet for the Flickr service.

 photoexp

If you’d like to view the source just use Silverlight Spy.

Klaklakgroup.com Featured in Silverlight.net Showcase

Sweet! Check it out.

Centered Silverlight 2.0 Content Revisited

After a while I realised that there was a problem with the “scale-9 grid” approach to centered content I wrote about previously.
I noticed little pixel-wide gaps were visible between bits of UI and lines of text weren’t always aligning with each other.

This was due to the grid positioning the content using un-rounded decimal values. The answer to getting everything centered AND pixel-perfect was going to have to be through code:

public Main()
{
    InitializeComponent();
    System.Windows.
Application.Current.Host.Content.Resized += new EventHandler(Content_Resized);
}

void Content_Resized(object sender, System.EventArgs e)
{
   
double browserWidth = System.Windows.Application.Current.Host.Content.ActualWidth;
   
double browserHeight = System.Windows.Application.Current.Host.Content.ActualHeight;

    double top = Math.Floor((browserHeight – UI.ActualHeight) / 2);
   
double left = Math.Floor((browserWidth – UI.ActualWidth) / 2);

    UI.SetValue(System.Windows.Controls.Canvas.TopProperty, top);
    UI.SetValue(System.Windows.Controls.
Canvas.LeftProperty, left);
}

This assumes that your Silverlight control is set to be 100% height and width of the browser window. You also need to have a root Canvas with a nested Grid or Canvas named “UI”.

A Simple Silverlight Tab Menu

Tab menus are a common design feature for many web sites. I wasn’t able to find a Tab Menu control with source anywhere so I created my own using the built in Silverlight controls. Here’s how I’ve done it:

Add a StackPanel to your Xaml page.

<StackPanel x:Name=”MainMenu” Orientation=”Horizontal” />

In the CodeBehind for that page add the following:

private void BindMenu()
{
    string[] menuItems = “Home, About Us, Products, Services, Contact”.Split(‘,’);   

    foreach (string item in menuItems)
    {
        RadioButton btn = new RadioButton();
        btn.Content = item;
        btn.Checked +=
new RoutedEventHandler(MainMenu_SelectionChanged);
        btn.GroupName =
“Main Menu”;
        btn.DataContext = item;
        btn.Margin =
new System.Windows.Thickness(0, 0, 2, 0);
        btn.Padding =
new System.Windows.Thickness(6, 6, 6, 4);
        btn.MinWidth = 60;
        btn.Style = (
Style)Application.Current.Resources["MainMenuTab"];
       
       
MainMenu.Children.Add(btn);
    }
}

void MainMenu_SelectionChanged(object sender, RoutedEventArgs e)
{
    string name = (String)((RadioButton)sender).DataContext;
}

Call the BindMenu() function from your Page_Loaded() function.

You can see that all I’m doing is getting an array of page names then iterating over them to create a RadioButton for each then adding that RadioButton to the previously defined StackPanel. The DataContext property is in this case being set to the string item but you could set this to be any complex object.

Just before adding the RadioButton to the StackPanel you can see that I’m setting it’s Style property to

Application.Current.Resources["MainMenuTab"];

This Style is contained in the App.xaml file and looks like this:

<Application.Resources>
    <Style x:Key=”MainMenuTab” TargetType=”RadioButton”>
        <Setter Property=”IsEnabled” Value=”true” />
        <Setter Property=”IsTabStop” Value=”true” />
        <Setter Property=”Foreground” Value=”Black” />
        <Setter Property=”Margin” Value=”0″ />
        <Setter Property=”MinWidth” Value=”0″ />
        <Setter Property=”HorizontalContentAlignment” Value=”Center” />
        <Setter Property=”VerticalContentAlignment” Value=”Center” />
        <Setter Property=”Cursor” Value=”Hand” />
        <Setter Property=”TextAlignment” Value=”Left” />
        <Setter Property=”TextWrapping” Value=”NoWrap” />
        <Setter Property=”FontSize” Value=”11″ />
        <Setter Property=”FontFamily” Value=”Verdana”/>
        <Setter Property=”Template”>
            <Setter.Value>
                <ControlTemplate TargetType=”RadioButton”>
                    <Grid x:Name=”RootElement” Cursor=”{TemplateBinding Cursor}”>
                        <Grid.Resources>
                            <Storyboard x:Name=”Normal State”/>
                            <Storyboard x:Name=”Checked State”>
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetName=”Checked” Storyboard.TargetProperty=”(UIElement.Opacity)” BeginTime=”00:00:00″ Duration=”00:00:00.1000000″>
                                    <SplineDoubleKeyFrame KeyTime=”00:00:00.1″ Value=”1″/>
                                </DoubleAnimationUsingKeyFrames>
                            </Storyboard>
                            <Storyboard x:Name=”MouseOver Checked State”>
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetName=”Checked” Storyboard.TargetProperty=”(UIElement.Opacity)” BeginTime=”00:00:00″ Duration=”00:00:00.0000000″>
                                    <SplineDoubleKeyFrame KeyTime=”00:00:00″ Value=”1″/>
                                </DoubleAnimationUsingKeyFrames>
                            </Storyboard>
                            <Storyboard x:Name=”Pressed Checked State”>
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetName=”Checked” Storyboard.TargetProperty=”(UIElement.Opacity)” BeginTime=”00:00:00″ Duration=”00:00:00.0000000″>
                                    <SplineDoubleKeyFrame KeyTime=”00:00:00″ Value=”1″/>
                                </DoubleAnimationUsingKeyFrames>
                            </Storyboard>
                            <Storyboard x:Name=”MouseOver Unchecked State”>                                  
                               
<DoubleAnimationUsingKeyFrames Storyboard.TargetName=”Checked” Storyboard.TargetProperty=”(UIElement.Opacity)” BeginTime=”00:00:00″ Duration=”00:00:00.5000000″>
                                    <SplineDoubleKeyFrame KeyTime=”00:00:00.1″ Value=”0.5″/>
                                </DoubleAnimationUsingKeyFrames>
                            </Storyboard>
                            <Storyboard x:Name=”Pressed Unchecked State”>
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetName=”Checked” Storyboard.TargetProperty=”(UIElement.Opacity)” BeginTime=”00:00:00″ Duration=”00:00:00.5000000″>
                                    <SplineDoubleKeyFrame KeyTime=”00:00:00.1″ Value=”1″/>
                                </DoubleAnimationUsingKeyFrames>
                            </Storyboard>
                            <Storyboard x:Name=”Disabled Unchecked State”>
                                <ColorAnimationUsingKeyFrames Storyboard.TargetName=”Unchecked” Storyboard.TargetProperty=”(Shape.Background).(SolidColorBrush.Color)” BeginTime=”00:00:00″ Duration=”00:00:00.0000000″>
                                    <SplineColorKeyFrame KeyTime=”00:00:00″ Value=”Gray”/>
                                </ColorAnimationUsingKeyFrames>
                            </Storyboard>
                            <Storyboard x:Name=”Disabled Checked State”>
                                <ColorAnimationUsingKeyFrames Storyboard.TargetName=”Unchecked” Storyboard.TargetProperty=”(Shape.Background).(SolidColorBrush.Color)” BeginTime=”00:00:00″ Duration=”00:00:00.0000000″>
                                    <SplineColorKeyFrame KeyTime=”00:00:00″ Value=”Gray”/>
                                </ColorAnimationUsingKeyFrames>
                            </Storyboard>
                        </Grid.Resources>
                        <Border x:Name=”Unchecked”
                           Opacity=”1″
                           BorderBrush=”BurlyWood”
                           BorderThickness=”1,1,1,0″
                           Background=”Beige”
                           CornerRadius=”4,4,0,0″>
                        </Border>
                        <Border x:Name=”Checked”
                           Opacity=”0″
                           BorderBrush=”BurlyWood”
                           BorderThickness=”1,1,1,0″
                           Background=”White”
                           CornerRadius=”4,4,0,0″>
                        </Border>
                        <ContentPresenter
                         Content=”{TemplateBinding Content}”
                         ContentTemplate=”{TemplateBinding ContentTemplate}”
                         Background=”Transparent”
                         FontFamily=”{TemplateBinding FontFamily}”
                         FontSize=”{TemplateBinding FontSize}”
                         FontStretch=”{TemplateBinding FontStretch}”
                         FontStyle=”{TemplateBinding FontStyle}”
                         FontWeight=”{TemplateBinding FontWeight}”
                         Foreground=”{TemplateBinding Foreground}”
                         HorizontalContentAlignment=”{TemplateBinding HorizontalContentAlignment}”
                         Padding=”{TemplateBinding Padding}”
                         TextAlignment=”{TemplateBinding TextAlignment}”
                         TextDecorations=”{TemplateBinding TextDecorations}”
                         TextWrapping=”{TemplateBinding TextWrapping}”
                         VerticalContentAlignment=”{TemplateBinding VerticalContentAlignment}”
                         Margin=”{TemplateBinding Margin}”
                         IsHitTestVisible=”true”
                         MinWidth=”{TemplateBinding MinWidth}”/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Application.Resources>

All I’ve done here is taken the default RadioButton style downloaded from here, removed the requisite ellipses and replaced them with Border controls. I’ve also adjusted the various state StoryBoards to target these Borders. The Borders are the familiar rounded tab shape surrounding the text and the StoryBoards define their mouseover, pressed and disabled states. RadioButtons are ideal for this purpose because they contain all the toggling functionality that a simple tab menu requires.

This is what it should look like:

tabstrip

Clicking on each tab will animate it to white and toggle the previously selected tab. Mousing over a tab turns it 50% white. I personally prefer tabs to be all the same width regardless of their text content. You can make each tab’s width match it’s text by setting each RadioButton’s MinWidth to 0 or just omitting MinWidth. It’s also worth noting that you don’t have to have tab backgrounds at all and can just use this as a handy way of creating horizontal lists of text-only buttons.

From here you could use the MainMenu_SelectionChanged event handler to show/hide corresponding Canvas controls when the tabs are toggled.

I may turn this into a more generic reusable TabMenu control in future but for now this is a pretty good way to get quick results.

Download the source code here

Centered Silverlight 2.0 Content

A very common layout for Flash sites is to center a rectangle of content horizontally and vertically in the browser window.

centered

I noticed that a method for doing this for Silverlight using css was posted here: http://michaelsync.net/2008/03/17/tipstricks-how-to-center-silverlight-control-on-a-webpage

This approach is good but I thought I’d suggest an alternative more in keeping with our particular way of working.

For Flash sites we tend to prefer to make the movie fill the entire window and then use actionscript to center the rectangle rather than css. We’ve found that the extra screen real-estate for Flash to redraw doesn’t significantly effect performance because of Flash’s “dirty rectangles” system. It’s also worth noting that the full-browser approach is a common practice for many Flex apps.

Here’s a simple way of getting this effect in Silverlight.

Set the width and height properties of your Silverlight control to 100%. Then in the root UserControl create a (scale 9) Grid like this:

<UserControl x:Class=”LayoutRoot”
xmlns=”http://schemas.microsoft.com/client/2007&#8243;    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”&gt;
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width=”*”/>
            <ColumnDefinition Width=”800″/>
            <ColumnDefinition Width=”*”/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height=”*”/>
            <RowDefinition Height=”600″/>
            <RowDefinition Height=”*”/>
        </Grid.RowDefinitions>      
       
<Canvas Grid.Column=”1″
           Grid.Row=”1″>
            <!– Content goes here –>
        </Canvas>
    </Grid>
</
UserControl>

Leave the root UserControl’s width and height properties blank so it stretches to fill the available space.

Update:

In order to get rid of the default margins of your page so the Silverlight control fills it completely you could use css like the following:

   
/* hide from ie on mac \*/
html {
   
height: 100%;
   
overflow: hidden;
    }

#SilverlightControlHost {
   
height: 100%;
   
width: 100%;
    }
/* end hide */

body {
   
height: 100%;
   
margin: 0;
   
padding: 0;
    }

This is the same as the css we use for Flash sites except the div wrapping the plugin has been renamed “SilverlightControlHost”.

Follow

Get every new post delivered to your Inbox.