Jeff Blankenburg is a passionate technologist with a wide range of interests.
This website is dedicated to discussing the ideas that pass through his head.

The main header for this website was created using Microsoft Silverlight.
Install it to see what you're missing!

Get Silverlight to see the whole site!

Day #2: Silverlight Screen Transitions

Thursday, July 02, 2009

This is second of thirty-one posts on Silverlight I will be doing in July. The first post was on the mouse events available to you in Silverlight. Today's post is on Screen Transitions, or more specifically, moving from one XAML file to another.

Moving From One XAML File To Another

This is the simple part. In your Silverlight project (mine is called SilverlightScreenTransitions), add a new XAML file. You can do this by right clicking on the project name, and choosing "Add > New Item." You won't see "XAML File" as one of the choices, because each XAML file in Silverlight is considered a User Control. So choose "Silverlight User Control," and give it a meaningful name, like page2.xaml. :)

Now jump back into your default XAML file, Page.xaml. We need a button, or a link, or something that will allow us to navigation to our new page. Here's the new XAML for our default page:

<UserControl x:Class="SilverlightScreenTransitions.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<
Canvas x:Name="LayoutRoot" Background="White">
<
Rectangle x:Name="Clicky" Width="200" Height="50" Fill="Red" Canvas.Top="125" Canvas.Left="100" Stroke="Black" StrokeThickness="4" MouseLeftButtonUp="Clicky_MouseLeftButtonUp"/>
</
Canvas>
</
UserControl>


All this does is put a red rectangle in the middle of our control. Next, we're going to need to edit our second page. We'll just put a "Congratulations!" textbox on the page, so we know we made it. Here's the XAML for Page2.xaml:

<UserControl x:Class="SilverlightScreenTransitions.Page2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<
Canvas x:Name="LayoutRoot" Background="White">
<
TextBlock Width="200" Height="50" Canvas.Top="125" Canvas.Left="100" Text="Congratulations!" TextAlignment="Center" FontSize="25"/>
</
Canvas>
</
UserControl>


The magic line of code

At this point, we have two XAML files, one with a rectangle (with an event handler), and the other with just a TextBlock. When we click on the Rectangle, we want to go to the other XAML file. Here's how you do it (in VB.NET, just ignore the semi-colon). Just add this line to your event handler code in Page.xaml.cs (or .vb):

this.Content = new Page2();


I thought this post was about transitions...

Oh, patience, my friends. Now that we know how to get from one screen to another, we can talk about transitions. Let me first start by defining transition:

The animated movement from one XAML file to another. Think transitions in Powerpoint. Fades, Dissolves, etc. We'll create an example of that in this post.

Fading In and Out

We're going to create a fading transition from the first slide to the second. What I'm going to do is create an animation in each XAML file. In Page.xaml, we'll create an animation that fades out. In Page2.xaml, we'll create an animation that fades it in. Between the two, we'll jump from one file to the next, using the code we wrote earlier.

Page.xaml animation

The only difference is the new Storyboard I created. It just takes the opacity of the LayoutRoot element from 100% to 0% in one second:

<UserControl x:Class="SilverlightScreenTransitions.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<
UserControl.Resources>
<
Storyboard x:Name="FadeOut">
<
DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(UIElement.Opacity)">
<
SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
<
SplineDoubleKeyFrame KeyTime="00:00:01" Value="0"/>
</
DoubleAnimationUsingKeyFrames>
</
Storyboard>
</
UserControl.Resources>
<
Canvas x:Name="LayoutRoot" Background="White" Opacity="1">
<
Rectangle x:Name="Clicky" Width="200" Height="50" Fill="Red" Canvas.Top="125" Canvas.Left="100" Stroke="Black" StrokeThickness="4" MouseLeftButtonUp="Clicky_MouseLeftButtonUp"/>
</
Canvas>
</
UserControl>


Page2.xaml animation

We are doing the exact opposite animation for this file, but there's one other thing to consider in this case. Even though our animation takes the opacity from 0% to 100%, we need to make sure that the initial opacity of our LayoutRoot element is set to 0%. Without that, the XAML file will load with it at 100%, and then the animation will kick off, fading it from 0 to 100. Not exactly the desired effect. So you'll see the opacity specified in the LayoutRoot element as well.

<UserControl x:Class="SilverlightScreenTransitions.Page2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<
UserControl.Resources>
<
Storyboard x:Name="FadeIn">
<
DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(UIElement.Opacity)">
<
SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
<
SplineDoubleKeyFrame KeyTime="00:00:01" Value="1"/>
</
DoubleAnimationUsingKeyFrames>
</
Storyboard>
</
UserControl.Resources>
<
Canvas x:Name="LayoutRoot" Background="White" Opacity="0">
<
TextBlock Width="200" Height="50" Canvas.Top="125" Canvas.Left="100" Text="Congratulations!" TextAlignment="Center" FontSize="25"/>
</
Canvas>
</
UserControl>


An Animation Event Handler?

So we obviously also need to change our code-behind, so that when we click, we call the animation. But how do we know when the animation is done? Well, we know it's going to take exactly ONE second, so technically, we could create a timer, wait 1 second, and then make the call to the second XAML file. But that's messy, and depending on ANY sort of lag, would be inaccurate. Thankfully, we have the ability to add event handlers to our animations as well. So, we can create a "Completed" event handler on our FadeOut animation, which will get called immediately after the animation completes. No guess work. Here's our new code-behind:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightScreenTransitions
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
FadeOut.Completed += new EventHandler(FadeOut_Completed);
}

void FadeOut_Completed(object sender, EventArgs e)
{
this.Content = new Page2();
}

private void Clicky_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
FadeOut.Begin();
}
}
}


Catching the animation on the other side

Transitioning into the next XAML file is simple, in the initial method, we call the FadeOut animation we created.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightScreenTransitions
{
public partial class Page2 : UserControl
{
public Page2()
{
InitializeComponent();
FadeIn.Begin();
}
}
}


The final working example

Below is the Silverlight application, up and running. If you're viewing this in an RSS reader, it may not show up, but you can click here to see the Silverlight Screen Transition working. You can also download all of the source code for this project here.







Get Microsoft Silverlight

Labels: , ,

posted by Jeff Blankenburg, 1:00 AM

8 Comments:

thanks for your tutorials, very nice!
commented by Blogger babba, 6:24 PM  


Thank you very much!
commented by Blogger Victor_Plotinsky05, 12:38 AM  


Awesome!

Thank you Jeff for sharing your hard work.

David Roh
commented by Anonymous Anonymous, 7:17 AM  


If you assign this.Content doesn't this make the new UserControl a child of the current userControl? And if you had a long-running app with lots of transitions, wouldn't this mean you end up with every page instance hanging around because they're all still linked in the tree? Along with any instance data they might have.
commented by Blogger Jim Lynn, 8:22 AM  


Jim,

I completely agree. I actually have a future tutorial that discusses this exact topic. Keep your eyes on June 12th's post.

Each of these posts is meant to show how to do one small thing very well. In the context of specific examples (like yours), there will always be "better" ways to handle the scenario with extra variables.

Hopefully my next post (#12) will address that for ya. Sorry for the confusion.
commented by Blogger Jeff Blankenburg, 8:29 AM  


thanks a bunch.. saved a lot of my time :)
Keep it up :)
commented by Blogger kamraj, 10:06 AM  


How should we do with following line in VB?
FadeOut.Completed += new EventHandler(FadeOut_Completed);

Thanks!
commented by Anonymous Anonymous, 3:00 PM  


I found the answer to my above question, the VB version of

FadeOut.Completed += new EventHandler(FadeOut_Completed);

should be

AddHandler FadeOut.Completed, AddressOf FadeOut_Completed
commented by Anonymous Anonymous, 3:21 PM  


Add a comment


Search

My Sponsor


My Badges



Follow Jeff Blankenburg on Twitter