Tuesday, September 13, 2011

Silverlight in Windows 8

I'm watching the BUILD conference online and they've just covered some details about the new Windows 8 Platform and App Store. There have been rumors about this store and what technologies it will support. It turns out the developer has a number of options.

There are two categories of apps:
  1. Metro style apps
  2. Desktop apps

Desktop apps are what we're all familiar with now in Windows 7 and past versions of Windows. Metro-style apps are touch-enabled and have fluid interfaces that mimic Windows Phone 7.

As for the technologies that these apps can be built with, this image from the conference sums it up pretty well...

They've demoed a couple apps so far in the conference. One was a simple HTML5/Javascript app called PhotoDoodle. The other was a Silverlight app that was actually taken from Scott Guthrie's blog from a series of posts a couple years ago. The cool part is that they were able to take Scott's code and make a XAML-based Metro style app out of it with minimal code changes. Some of the API's and Namespaces are a little different so there are some feature checks in place like this...

Some Silverlight developers were worried that the App Store would only support HTML5, but clearly that's not the case. XAML has its place on Windows 8 as well.

Sunday, June 26, 2011

Introducing XAML Illustrations, Increased Payouts to Contributors, and More

For the past couple months I've been working on a new design for SilverlightXAP.com.  And today I'm proud to say it's done!



It's a completely new look, but beyond that I aimed to make a number of improvements and solve a number of problems.

XAML Illustrations
First and foremost, I knew I needed to expand the product range.  The most logical step was to add XAML illustrations to the mix.  The idea is to provide royalty-free illustrations in 100% vector format and coded in XAML.  This makes things extra easy for developers to drop beautiful vector graphics into their Silverlight project.  At this point there's just one illustration in the collection, which is derived from some simple icons I had designed months ago for Regex Hero.  Sign up to submit your own illustrations.

85% Payouts to Contributing Members
As a special promotion we're paying 85% of the proceeds from every product you sell through the site.  This deal will last through the rest of 2011, after which the rate will decrease to the standard 70%.  Once again, if you're not already signed up and want to sell your work on the site, sign up here.

Faster Silverlight Load Times
Now we'll get a little technical.  I spent some time optimizing a number of areas of the site.  First, I changed the way the XAP files are delivered. Rather than streaming the XAP file out of the database, I'm now delivering them straight from the file system on the server (IIS is able to do this much more efficiently).  Plus this allows the preloading animation to load properly and I think this improves perceived performance as a result.

Faster Product Page Load Times
Next up I redesigned the online support system.  The support system was inspired by GetSatisfaction, which is a service that streamlines support requests.  Much like GetSatisfaction, I have support requests divided into 4 categories: reviews, questions, ideas, and problems.  Initially I had created this system with a lot of AJAX, and it worked pretty well.  There were, however, some bugs and strange behavior in some browsers.  I could've fixed these problems with a little time and effort.  But all of this functionality built into the already heavy product pages caused the whole page to load slower than I'd like.  So in fact I ripped out the AJAX in favor of a greatly simplified approach composed of multiple pages.  I was able to ditch a whole lot of Javascript as a result, and the product pages load much faster now.

Faster Everywhere
Last, but certainly not least, I've moved much of the common images, js, and css files over to a CDN (content delivery network).  I went with RackSpace Cloud Files.  They're using the excellent and always fast Akamai network with servers in 72 countries.  The result should be a marked improvement in every page of the site.  But the improvement will be felt even more in countries outside the U.S.

Friday, April 1, 2011

March 2011 Contest Results

First of all, thanks goes to everyone who has contributed to SilverlightXAP.com.  This site has been a vision of mine for over a year and I'm excited to see it come alive.

The contest was a bit ambitious as it turns out.  There have been 19 products submitted to the site coming from 3 people.  But there was only one sale.  A single license of the excellent Silverlight Wizard Carousel by Bob DeCuir was purchased about a week ago.

With that said, I can announce a winner...

1st place
Bob DeCuir
Tampa, FLwww.neufundmanager.com
Bob has a $1,000 check coming his way.  Since there weren't any other sales I can't announce 2nd and 3rd place winners.  But I'm still giving $50 Amazon gift cards to Zachary Bauer and Tom Jorgenson for all their hard work and contributions.  These 3 guys have helped jump start this site and I think they all deserve recognition for that.  Thanks again guys!

Tuesday, February 22, 2011

An Interview with Jeff Wilcox

Jeff is a Senior Software Development Engineer at Microsoft, on the Silverlight Phone & Devices Team. A founding member of the Silverlight Toolkit team, Jeff runs the Silverlight for Windows Phone Toolkit, created several controls in the Silverlight and Windows Phone SDKs, and wrote the Silverlight Unit Test Framework. Jeff lives in Seattle, WA, USA.  You can find more from Jeff at www.jeff.wilcox.name


I interviewed Jeff about his work with Silverlight, the Silverlight Toolkit, and his ongoing efforts at Microsoft.  Though unofficial, below are his thoughts on the subject.


Q. I understand you were a major player in the creation of the Silverlight Toolkit.  Is that still going on, or what are you doing now?
A. We last shipped a desktop Silverlight Toolkit in April 2010, and it's received hundreds of thousands of downloads. Since then, we've all been focusing on the Silverlight for Windows Phone - both the app platform as well as building the initial Silverlight for Windows Phone Toolkit.

We just shipped the latest Silverlight for Windows Phone Toolkit last week, it's called the February 2011 release. It shares some code with the desktop toolkit, such as WrapPanel and AutoCompleteBox.

A lot of the early work we did on the Windows Phone application platform really ended up helping us better understand the unique performance considerations for the phone, and the phone toolkit is being used by a majority of the important phone apps out there like Twitter and Facebook.


Q. The Silverlight Toolkit is a brilliant collection of free controls.  I'm sure it has taken a long, long time to build them all.  What tips could you give other control developers looking to build controls of the same quality?
A. One of the best things we did early was try and make it clear that the Silverlight Toolkit is a special product: it isn't an officially supported product, and that allows us to define the quality bands (such as experimental, and mature). By offering the source code, we allow people who find important issues to make the fixes they need, but it also lets us ship controls like the Accordion that maybe weren't at the highest level of quality yet.

I believe the most important thing other developers can do is try and really grok what it means to build a lookless control: it's a unique skill, there are a lot of design decisions to be made, and you really just need to practice. Doing application building, along with a set of controls for that app, is a great way to get up to speed on control dev.

So lots of practice.

I also have often referred people to the control source code at http://silverlight.codeplex.com/ - yeah, there are some bugs, but it's a good set of different concepts, strategies, and a starting place. The "Common" code files and helpers often end up in other people's controls, they're really helpful for working with the visual tree, visual state manager, etc.

We actually had a number of challenges, if you look through the source code you can tell that there are distinct developers who worked on the project, and it's always a lot of fun (heated arguments included) trying to define the guidelines, what code style we like, and working together on such a big set of deliverables, but over time it all came together.

Now we're mostly just looking at the future and the Windows Phone work has been a fun way to see just how easily it is to reuse those same Silverlight skills. Biggest difference is considering the form factor, touch manipulations, and concepts that don't make sense on the phone (like focus).


Q. From my own experience, there are times when you're building an app that is very small in nature and you don't want unused components adding to the XAP size.  Perhaps it's an obsession on my part.  A couple developers always laughed when I described the effort that went into making Regex Hero under 50 KB at one point in time.  But what do you think of the SilverlightXAP approach of offering individual controls not a part of a larger control suite?
A. There's a lot to be said about the model. If you look at SilverlightXAP and code paste sites and NuGet.org, you find that .NET developers do enjoy a really simple way to get individual components, outside of a suite.

It also lets people mix and match components, and just keep what works for them, without heavy dependencies. I really like that.


Q. Silverlight is being used today on Windows, Mac, and Windows Phone 7.  I hear rumors it's coming to the XBOX 360, and my toaster oven.  I'd love for it to be on everything.  But where would you like to see Silverlight next?
A. While you are correct, we're on Mac, Windows, and Windows Phone 7 today, I can't comment on any official roadmap for where things are headed.

We're always experimenting on the development team - it's a pretty good collection of really smart developers. I don't think a lot of people understand just how much of Silverlight is written in native code. That is a great benefit to us, because it enables us to consider moving to other platforms as business needs dictate.

On the Silverlight Phone & Devices Team, we're hiring actually - http://bit.ly/sldevicedevjob :-)

Sunday, February 13, 2011

Silverlight 5, HTML5, and what the future may bring

Ever since PDC last year there's been stirring talk about Silverlight's future.  Some people think Silverlight's days are numbered with broad HTML5 support just around the corner.  These rumors have been perpetuated even today by those anxious to see HTML5 come to fruition.  And some irresponsible journalism may have been at play as well.

The controversy stemmed from three things at PDC10:
  1. Microsoft showed off IE9 and their commitment to HTML5.
  2. Other than Silverlight's involvement with Windows Phone 7, there weren't any major Silverlight announcements.
  3. In an interview Bob Muglia was quoted as saying, "Our Silverlight strategy and focus going forward has shifted."
And from that many people assumed Silverlight was as good as dead.  It's a wild conclusion if you ask me.  And sure enough, Bob Muglia then wrote an article stating that he was misunderstood, and that Silverlight is still very important to Microsoft.   Despite his statements and others from those such as Scott Guthrie and Tim Heuer, the rumors continued.

Then in December, Microsoft held their scheduled Silverlight Firestarter event where they demonstrated upcoming features of Silverlight 5.  They're bringing a bunch of new features I'm looking forward to.  The most visually stunning will be a new GPU-accelerated 3D API built directly into Silverlight.  The fact that they're continuing to bring innovations like this creates a strong case for Silverlight's future.  

At this point I'm reminded of the nature of technical innovation, and history's tendency to repeat itself.  In 1996, a young company named Macromedia created a little browser plug-in called Flash.  They created it because of the inherent limitations of HTML, Javascript, and their lack of standardization at the time.  Flash brought a new level of capabilities to the web.  And as time went on it became more ubiquitous than Java, Adobe Reader, or practically any other component you can think of.  The need for something like Flash has lived on to this day (15 years later) because of the relative slow pace of browser innovations.  (Brad Becker has a great article that touches on this paradigm in greater detail.)

The HTML5 era will be a giant leap forward for the HTML/Javascript duo.  That much is certain.  And it'll be a good thing for the web.  But as long as there's more than one browser out there and there's a need for standardization bodies, innovation with HTML will always be slower than plugins like Silverlight and Flash.  That's the truth.  And that's why Silverlight lives on.

Wednesday, February 9, 2011

New RSS Subscriptions for Search

I love TiVo.  In particular I like their wishlist search.  You can search for a movie or TV show you want to see by keyword, title, actor, etc.  And even if it's nowhere to be found in TiVo's two weeks of guide data you can still create a wishlist out of it.  Then anything that matches your search in the future will automatically be recorded.

Well, in much the same fashion I've created RSS subscriptions for SilverlightXAP.  If you search our collection of controls you'll always see a "Subscribe via RSS" link in the lower-left hand corner.  And just like TiVo, this even works when there are no results to be found.

To take this a step further I'll soon be creating statistics that registered SilverlightXAP developers can view based off of these subscriptions.  The idea is that developers can view popular searches and see what people are looking for.  They can then create a control that a bunch of people want, and those people will automatically be notified when the control is published.

Thursday, January 27, 2011

Mastering Storyboards One Mistake at a Time

I've always been interested in animation. I wrote over 100 programs in QBASIC and Turbo C++ as a teenager where I was creating various animations and exploring new techniques. Then I graduated to newer technologies like OpenGL, Flash, and much later -- Silverlight.

I almost became a game programmer, and probably would have if I didn't have to relocate. But anyway, as time goes on you begin to understand what tools to use and when. And obviously animation is necessary in today's video games, but it's not something that should be overused in other applications. Still, I contend that when used in moderation, it can be a nice finishing touch.

Storyboards

Storyboards in Silverlight are a simple, declarative way to define animation sequences. They can be used to animate just about any property on a UIElement.

I'm going to walk through a few Storyboard examples that build upon eachother while pointing out several different techniques (some better than others). The goal is not to cover every technical possibility with Silverlight. Rather, it's to intentionally run into common technical, design, or usability mistakes and finally arrive at something that's pretty good.

In my examples below I chose to animate the Opacity property. The Opacity property is simply a double value that accepts any number between 0 (transparent) and 1 (opaque).

I'm going to create a set of images and captions, where both the image and caption will fade their opacity to 1 (opaque) as you mouseover them. I also want them to be clickable to open a bigger image.

Example 1


This first attempt is simple and straightforward.

First, I create my images and captions in XAML:

<Grid x:Name="LayoutRoot" Background="Black">
 <StackPanel HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10">
  <StackPanel Orientation="Horizontal">
   <Image x:Name="Image1" Opacity="0.5" Height="100" Width="100" Margin="10,1" Source="http://swortham.smugmug.com/Vacation/Santa-Cruz-Island-2010/011/788697398_xPrbE-Tiny.jpg"/>
   <TextBlock x:Name="Caption1" Opacity="0.5" VerticalAlignment="Center" Width="250" Text="I arrived on Santa Cruz Island and after just a few minutes I stumbled across this view." TextWrapping="Wrap" />
  </StackPanel>
  <StackPanel Orientation="Horizontal">
   <Image x:Name="Image2" Opacity="0.5" Height="100" Width="100" Margin="10,1" Source="http://swortham.smugmug.com/Vacation/Santa-Cruz-Island-2010/136/789417908_3bjhd-Tiny.jpg"/>
   <TextBlock x:Name="Caption2" Opacity="0.5" VerticalAlignment="Center" Width="250" Text="But there was much more coast and wildlife to see, so I hiked for hours." TextWrapping="Wrap" />
  </StackPanel>
  <StackPanel Orientation="Horizontal">
   <Image x:Name="Image3" Opacity="0.5" Height="100" Width="100" Margin="10,1" Source="http://swortham.smugmug.com/Vacation/Santa-Cruz-Island-2010/088/789378275_maquH-Tiny.jpg"/>
   <TextBlock x:Name="Caption3" Opacity="0.5" VerticalAlignment="Center" Width="250" Text="Then I relaxed a bit." TextWrapping="Wrap" />
  </StackPanel>
 </StackPanel>
</Grid>

Then, I create storyboards for each:

<UserControl.Resources>
  <Storyboard x:Name="ImageRollover1">
   <DoubleAnimation Storyboard.TargetName="Image1" Storyboard.TargetProperty="Opacity" From="0.5" To="1" Duration="00:00:00.750000" />
   <DoubleAnimation Storyboard.TargetName="Caption1" Storyboard.TargetProperty="Opacity" From="0.5" To="1" Duration="00:00:00.750000" />
  </Storyboard>
  <Storyboard x:Name="ImageRollout1">
   <DoubleAnimation Storyboard.TargetName="Image1" Storyboard.TargetProperty="Opacity" From="1" To="0.5" Duration="00:00:00.750000" />
   <DoubleAnimation Storyboard.TargetName="Caption1" Storyboard.TargetProperty="Opacity" From="1" To="0.5" Duration="00:00:00.750000" />
  </Storyboard>
  <Storyboard x:Name="ImageRollover2">
   <DoubleAnimation Storyboard.TargetName="Image2" Storyboard.TargetProperty="Opacity" From="0.5" To="1" Duration="00:00:00.750000" />
   <DoubleAnimation Storyboard.TargetName="Caption2" Storyboard.TargetProperty="Opacity" From="0.5" To="1" Duration="00:00:00.750000" />
  </Storyboard>
  <Storyboard x:Name="ImageRollout2">
   <DoubleAnimation Storyboard.TargetName="Image2" Storyboard.TargetProperty="Opacity" From="1" To="0.5" Duration="00:00:00.750000" />
   <DoubleAnimation Storyboard.TargetName="Caption2" Storyboard.TargetProperty="Opacity" From="1" To="0.5" Duration="00:00:00.750000" />
  </Storyboard>
  <Storyboard x:Name="ImageRollover3">
   <DoubleAnimation Storyboard.TargetName="Image3" Storyboard.TargetProperty="Opacity" From="0.5" To="1" Duration="00:00:00.750000" />
   <DoubleAnimation Storyboard.TargetName="Caption3" Storyboard.TargetProperty="Opacity" From="0.5" To="1" Duration="00:00:00.750000" />
  </Storyboard>
  <Storyboard x:Name="ImageRollout3">
   <DoubleAnimation Storyboard.TargetName="Image3" Storyboard.TargetProperty="Opacity" From="1" To="0.5" Duration="00:00:00.750000" />
   <DoubleAnimation Storyboard.TargetName="Caption3" Storyboard.TargetProperty="Opacity" From="1" To="0.5" Duration="00:00:00.750000" />
  </Storyboard>
 </UserControl.Resources>

And as a last step I wire the MouseEnter and MouseLeave events in the codebehind:
public MainPage()
  {
   InitializeComponent();

   Image1.MouseEnter += Image1_MouseEnter;
   Image1.MouseLeave += Image1_MouseLeave;

   Image2.MouseEnter += Image2_MouseEnter;
   Image2.MouseLeave += Image2_MouseLeave;

   Image3.MouseEnter += Image3_MouseEnter;
   Image3.MouseLeave += Image3_MouseLeave;
  }

  private void Image1_MouseEnter(object sender, MouseEventArgs e)
  {
   ImageRollover1.Begin();
  }
  private void Image1_MouseLeave(object sender, MouseEventArgs e)
  {
   ImageRollout1.Begin();
  }

  private void Image2_MouseEnter(object sender, MouseEventArgs e)
  {
   ImageRollover2.Begin();
  }
  private void Image2_MouseLeave(object sender, MouseEventArgs e)
  {
   ImageRollout2.Begin();
  }

  private void Image3_MouseEnter(object sender, MouseEventArgs e)
  {
   ImageRollover3.Begin();
  }
  private void Image3_MouseLeave(object sender, MouseEventArgs e)
  {
   ImageRollout3.Begin();
  }

And here's the result:

Get Microsoft Silverlight

These pictures came from a trip to California last year to attend an SEO course by Bruce Clay (but I also made a vacation out of it).

Anyway, as you can see it does work. However, there are a few problems:
  1. The mouseover effect only works over the image.
  2. There's a lot of redundant code here. All of those storyboards are identical except for their TargetNames.
  3. With all that code, the images are still not clickable.


Example 2

So let's get a little more sophisticated with our approach. There's a built-in control that can help us. It's the HyperlinkButton.

Go ahead and add a HyperlinkButton to the page. And then right-click on it and click "Edit Template..." > "Edit a copy..."

(To do this you'll need Expression Blend. If you don't have it, don't worry, I'll still post the resulting XAML below.)

After doing that and removing and changing a few things, I end up with this:
<UserControl.Resources>             
        <Style x:Key="HyperlinkButtonRollover" TargetType="HyperlinkButton">
         <Setter Property="Foreground" Value="#FFF"/>
         <Setter Property="Padding" Value="0"/>
         <Setter Property="Cursor" Value="Hand"/>
         <Setter Property="Background" Value="Transparent"/>
         <Setter Property="Template">
          <Setter.Value>
           <ControlTemplate TargetType="HyperlinkButton">
            <Grid Background="{TemplateBinding Background}" Cursor="{TemplateBinding Cursor}">
             <VisualStateManager.VisualStateGroups>
              <VisualStateGroup x:Name="CommonStates">
               <VisualState x:Name="Normal">
                <Storyboard>
                 <DoubleAnimation Storyboard.TargetName="contentPresenter" Storyboard.TargetProperty="Opacity" From="1" To="0.5" Duration="00:00:00.750000" />
                </Storyboard>
               </VisualState>
               <VisualState x:Name="MouseOver">
                <Storyboard>
                 <DoubleAnimation Storyboard.TargetName="contentPresenter" Storyboard.TargetProperty="Opacity" From="0.5" To="1" Duration="00:00:00.750000" />
                </Storyboard>
               </VisualState>
              </VisualStateGroup>
             </VisualStateManager.VisualStateGroups>
             <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            </Grid>
           </ControlTemplate>
          </Setter.Value>
         </Setter>
        </Style>
    </UserControl.Resources>

One of the cool things about this approach is the VisualStates built into the HyperlinkButton. By using the "Normal" and "MouseOver" states, I can actually get rid of all that code we had added earlier in the codebehind.

And then the XAML for the images and captions looks like this:
<Grid x:Name="LayoutRoot" Background="Black">
        <StackPanel HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10">
         <HyperlinkButton Style="{StaticResource HyperlinkButtonRollover}" NavigateUri="http://swortham.smugmug.com/Vacation/Santa-Cruz-Island-2010/011/788697398_xPrbE-L.jpg" TargetName="_blank">
          <HyperlinkButton.Content>
           <StackPanel Orientation="Horizontal">
                  <Image Height="100" Width="100" Margin="10,1" Source="http://swortham.smugmug.com/Vacation/Santa-Cruz-Island-2010/011/788697398_xPrbE-Tiny.jpg"/>
                  <TextBlock VerticalAlignment="Center" Width="250" Text="I arrived on Santa Cruz Island and after just a few minutes I stumbled across this view." TextWrapping="Wrap" />
              </StackPanel>
    </HyperlinkButton.Content>
         </HyperlinkButton>
   <HyperlinkButton Style="{StaticResource HyperlinkButtonRollover}" NavigateUri="http://swortham.smugmug.com/Vacation/Santa-Cruz-Island-2010/136/789417908_3bjhd-L.jpg" TargetName="_blank">
          <HyperlinkButton.Content>
           <StackPanel Orientation="Horizontal">
                  <Image Height="100" Width="100" Margin="10,1" Source="http://swortham.smugmug.com/Vacation/Santa-Cruz-Island-2010/136/789417908_3bjhd-Tiny.jpg"/>
                  <TextBlock VerticalAlignment="Center" Width="250" Text="But there was much more coast and wildlife to see, so I hiked for hours." TextWrapping="Wrap" />
              </StackPanel>
    </HyperlinkButton.Content>
         </HyperlinkButton>  
   <HyperlinkButton Style="{StaticResource HyperlinkButtonRollover}" NavigateUri="http://swortham.smugmug.com/Vacation/Santa-Cruz-Island-2010/088/789378275_maquH-L.jpg" TargetName="_blank">
          <HyperlinkButton.Content>
           <StackPanel Orientation="Horizontal">
                  <Image Height="100" Width="100" Margin="10,1" Source="http://swortham.smugmug.com/Vacation/Santa-Cruz-Island-2010/088/789378275_maquH-Tiny.jpg"/>
                  <TextBlock VerticalAlignment="Center" Width="250" Text="Then I relaxed a bit." TextWrapping="Wrap" />
              </StackPanel>
    </HyperlinkButton.Content>
         </HyperlinkButton>  
        </StackPanel>
    </Grid>

Get Microsoft Silverlight

With those modifications the XAML is looking a little neater and the app is more or less doing what I want.

The remaining problems are those of design and usability:
  1. If you mouseover every image very quickly you'll notice that they kind of flash abruptly. This is due to an oversight in our storyboards which we'll fix in the next example.
  2. The animations have a long duration. They are currently set at 0.75 seconds. That doesn't sound like a long time, but it feels like it when you're actually using the app. Slow transitions like this are fine in a loading screen, where the user can't do anything but wait. But when they're actually using your application, a slow animation can give the impression that your app is slow and unresponsive. The user may even feel like they must let the animation play in its entirety before clicking.
  3. The animation feels a bit robotic and unnatural.


Example 3

First we'll address the abrupt flashing we were experiencing. The problem occurs when you mouse over and then off of an element before its mouseover animation is done playing.

The problem is incredibly easy to solve, although the solution may not be obvious at first. All you have to do is remove the "From" attribute from the storyboards...

The "From" was causing the MouseOver and Normal states to always start at a specified Opacity. In reality, we simply don't care at what Opacity the animation starts. We only care that it ends.

Next I'll change the duration of the storyboards to 0.3 seconds for the "MouseOver" state and 0.5 seconds for the "Normal" state.

And last I'm going to specify some easing. Learning how to use easing makes the difference between robotic/abrupt feeling transitions, and a smooth user interface. I'm going to work with one of the simpler EasingFunctions, the CircleEase. And I'll use the EaseOut mode. By doing this, the majority of the animation occurs up front and then settles gradually. It's a subtle but noticeable difference.

The resulting changes were all in the Storyboards:
<UserControl.Resources>
        <Style x:Key="HyperlinkButtonRollover" TargetType="HyperlinkButton">
            <Setter Property="Foreground" Value="#FFF"/>
            <Setter Property="Padding" Value="1"/>
            <Setter Property="Cursor" Value="Hand"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="HyperlinkButton">
                        <Grid Background="{TemplateBinding Background}" Cursor="{TemplateBinding Cursor}">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal">
                                        <Storyboard>
                                            <DoubleAnimation Storyboard.TargetName="contentPresenter" Storyboard.TargetProperty="Opacity" To="0.5" Duration="00:00:00.500000">
                                             <DoubleAnimation.EasingFunction>
                                              <CircleEase EasingMode="EaseOut" />
            </DoubleAnimation.EasingFunction>
                                            </DoubleAnimation>          
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="MouseOver">
                                        <Storyboard>
                                            <DoubleAnimation Storyboard.TargetName="contentPresenter" Storyboard.TargetProperty="Opacity" To="1" Duration="00:00:00.300000">
                                             <DoubleAnimation.EasingFunction>
                                              <CircleEase EasingMode="EaseOut" />
            </DoubleAnimation.EasingFunction>
                                            </DoubleAnimation>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>

And the final app is here...
Get Microsoft Silverlight


I've packaged all of the projects above into one zip file...
Download MasteringStoryboards.zip



Bonus: Building it all into a Control

I thought it might be cool to animate the image and the caption separately, as if the image is sliding over and bumping into the caption. To do this while maintaining everything the HyperlinkButton gives us I've created a new custom control called the Captioned Image Hyperlink.