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

Silverlight 2.0 and the Internet OS

Scott Guthrie has announced the roadmap for a bunch of technologies including Silverlight 2.0.
http://weblogs.asp.net/scottgu/archive/2007/11/29/net-web-product-roadmap-asp-net-silverlight-iis7.aspx

The prospect of having a technology similar in many ways to Flash but with the .Net framework under the hood is a pretty enticing one. Inevitably we end up thinking about this as Adobe vs Microsoft and this is round one of a drawn-out “browser wars” style battle.

While discussing this prospect with a friend I likened (perhaps unjustly) the current state of affairs to the first days of the Apple Mac before Windows had made inroads into the desktop market. My conjecture was: If the Internet is the new Operating System, could Flash be the Mac of the Internet? Now, this is a highly contentious point and might be worth exploring a bit.

Ray Ozzie seems to get the Internet as Operating System idea and as Microsoft’s new Chief Software Architect has steered the super-tanker that is MS gradually onto a new course. If you take into account the number of key engineers that MS lost to Google and the reportedly lacklustre sales of Vista I’d say that people at the top are starting to get a bit antsy.

It seems that cloud computing is the new black and everyone’s racing to get a foothold ahead of the competition. Mobility seems to be one of the main driving forces behind this shift to the cloud. Intel recently announced their new “Ultra Mobile” chips hinting at an increasingly mobile future for computing. Google are most definitely betting on people wanting to store and retrieve their data online from their mobile devices. To anyone who thinks that people aren’t prepared to put sensitive data on the web I give you Facebook and Myspace. Are we heading inexorably for a world where our PC’s are in our pocket and all our data is in the cloud? Until someone figures out how to make a 22″ monitor and a usable keyboard fit into my pocket I think I’ll reserve judgement. Or failing that it becomes possible to interact with my machine though some form of neural-interface.

So the question from Microsoft’s perspective is: Assuming that the future is in the cloud, how do you go about beating the competition in this scary new world where you don’t necessarily hold all the keys for storing and manipulating people’s precious data? If you place any stock in Steve Ballmers frightening rants you’ll know that at MS it’s all about “developers developers developers”. MS knows that the way to win an Internet OS war is to win developers over to their platform, read Silverlight + Web Services.

Microsoft didn’t immediately understand the key importance of rich user interfaces. Apple were the first to do it for the PC and are still setting the agenda in this field, although perhaps the signs are there that Apple’s focus is shifting more toward mobile computing with the success of the IPhone, IPod and recent reports of uncharacteristic flaws in Leopard. Meanwhile Flash has evolved from a nice animation tool into something you can make visually rich applications like Word or Photoshop with. If you combine this new Flash with something like Amazon’s S3 service you’re one $100 laptop with an installation of Linux and Firefox away from cutting Microsoft out of the loop entirely. You just know that Adobe and Google are readying offers you can’t refuse to make this transition as tempting as possible. Admittedly you’re already cutting MS out of the loop using Linux or OSX, but this doesn’t to their minds currently represent a significant enough threat to their dominance. It’s the advent of the Internet OS that’s really shaking them.

For me Silverlight represents Microsoft’s entry to provide the user-interface for the new Internet OS (regardless of whether you’re using Windows, Linux or OSX) and thus reap the same rewards previously gained by controlling the user-interface for the majority of desktops. Is it even possible that Silverlight is the most important product to secure the future of MS? All I know is that Adobe are gonna have one hell of a fight on their hands to avoid becoming “the Mac of the Internet” and I look forward to reaping the innovative goodness that will hopefully come from both companies in order to win us over like the cheap tarts we are :-)

Follow

Get every new post delivered to your Inbox.