Centered Silverlight 2.0 Content Revisited

April 24, 2008 by edsilverton

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

April 1, 2008 by edsilverton

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

Squirrels are funny

March 27, 2008 by edsilverton

This little fella amuses us on a semi-regular basis as he (she?) larks about outside our window.
Here he is having a bit of a scratch and a stretch.

Every company should have its own squirrel.

Centered Silverlight 2.0 Content

March 25, 2008 by edsilverton

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″    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”>
    <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”.

Back to work

March 20, 2008 by edsilverton

Well I’m back from Mix08 in Vegas and my subsequent Italian snowboarding holiday and now I’m spelunking Silverlight 2 in preparation for some client work.

Mix08 was an incredible event and I thoroughly enjoyed meeting new people as well as friends who were attending. There was so much going on and being announced that it wouldn’t do it justice to summarise here.

From what I’ve seen Silverlight is going through a phase similar to the early days of Flash where developers are sharing tips and tricks and trying to settle on standard patterns and practices. However it feels like this process is on steroids due perhaps to the number of blogging asp.net developers. I’m trying to filter all this information into my own implementation of a Cms-driven site which I’ll give code samples for in due course.

Here are some particularly helpful Silverlight blogs I’ve come across:

http://www.cameronalbert.com/Default.aspx
http://blogs.msdn.com/dancre/default.aspx
http://community.irritatedvowel.com/blogs/pete_browns_blog/default.aspx
http://silverlightrocks.com/community/blogs/silverlight_games_101/default.aspx
http://geekswithblogs.net/WynApseTechnicalMusings/Default.aspx

Routed Events

January 28, 2008 by edsilverton

My intention for this blog was to write mainly about Silverlight as this is the most exciting technology for me being a .Net developer for a company that primarily makes RIA’s. Finally I’ll get to make the sexy front-end stuff again!  However after fiddling with Silverlight in its current form I quickly ran into a wall - the lack of Routed Events. This was a real showstopper for me as I want multiple listeners for single events like in Flash. This really stopped me in my tracks and I resolved to wait until Silverlight 2.0 came out and (hopefully) included this crucial functionality. There are solutions out there like this but my feeling about it is that I shouldn’t need to use a hack and this is symptomatic of the overall present alpha-ness of Silverlight. Better to wait until the platform is at least in Beta before committing a ton of time to learning it and bypassing its shortcomings. Until then I’ll continue to write speculative ruminations about technology :-)

I’m off to Mix08 in March which is all rather exciting. Sounds like we’re in for a huge amount of new stuff being released to coincide with Mix such as IIS7, Silverlight 2.0, Visual Studio 2008 etc. Should give me plenty to write about!

Something that’s been going around my head recently is why haven’t I heard about Blinq for Silverlight yet? Blinq is a system for generating Asp.Net web forms automatically to enable CRUD operations from a database schema. Linq (language Integrated Query) is the technology that enables this scenario. Silverlight 2.0 has Linq built in and will have form controls like text areas, drop down lists and datagrids. Surely it’s no biggy for someone to build a Blinq for Silverlight? Perhaps this will be announced at Mix. The prospect of having CRUD forms generated automatically then just needing to style them is a rather appealing one (at least to me).

The potential of desktop Linux + SAAS

December 11, 2007 by edsilverton

This article (via Slashdot) sums up my theory regarding the importance of Silverlight at Microsoft much better than I could.

Desktop Linux plus RIA/SAAS equals a free, lightweight and reliable operating system with many applications running on it of roughly comparable quality to those currently available on Windows or OSX. However, for this to become more than a niche market it depends on three assumptions as far as I can tell.

One, high speed Internet access is on course for being ubiquitous and people are comfortable with their sensitive personal data being transmitted over the web. Recent reports about the explosion of Internet Christmas shopping would seem to bear this out at least for the UK.

Two, all major desktop apps will eventually be rewritten as RIA’s. We’ve already seen that key business apps like Office and Photoshop are in the works. Apps like 3D Studio Max may take a lot longer to emerge, but I wouldn’t say that the absence of 3D Studio Max is much of a deal-breaker for people happy to use a cheap and cheerful laptop for all their computing.

Three, people are willing to pay for software as a subscription or put up with advertisements being in their face all day. In my opinion it won’t be long until we hear about people with a high tolerance for sponsored messages doing all their computing completely for free. Just browsing the web or using Google already exposes us to a lot of this, so it probably won’t be much of a leap.

Personally I look forward to a day when all operating systems are as lightweight as possible and only exist to provide the necessary substrate for runtimes like Flash, Silverlight or JavaFX. Microsoft’s Singularity project could be worth watching in this respect. Perhaps Web Development agencies will end up dropping the “Web” from their professional designation?

Live Documents

December 5, 2007 by edsilverton

Hello again. Just to follow up a bit on my previous post about the burgeoning “Internet OS” here’s a link to something I’m sure you probably already know all about:

http://www.live-documents.com/

This is basically a MS Office 2007 clone written in Flex/Flash and looks pretty nice from the screen-grabs.

Silverlight 2.0 and the Internet OS

November 30, 2007 by edsilverton

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

Hello world

November 29, 2007 by edsilverton

Not sure if this is a good idea or not, but I seem to remember that I enjoyed writing once so I’ll see if I can re-capture that. That’s a whole topic right there to talk about, why would I no longer enjoy writing? Is it because I spend my whole day writing emails that started off as being well-crafted and have gradually degenerated into time-saving bluntness? Has this created an association in my brain between writing my thoughts down and wasting time? I suppose I could start formulating a clichéd argument here that email, text-messaging, social networks and whatever other predominant technologies are slowly eroding our collective capacity for creative writing. Nah. New forms of communication can only be good, it’s when people don’t communicate that you get problems, isn’t it? Saying that though, I could do without those inane comments you get on youtube… Perhaps www.stupidfilter.org is the answer? Now, I don’t wish to presume anything about my reader, but don’t you sometimes wish you had a stupid-filter for yourself? I certainly do. It could bleep me whenever I say something in order to fill an uncomfortable silence, or even temporarily blind people with a flash of light as I spill a drink all over myself. Hmm, I am enjoying writing this. Yay!