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.
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.
thanks a bunch.. saved a lot of my time 🙂 Keep it up 🙂
thanks for your tutorials, very nice!
Sloth like rust, consumes faster than labor wears more body.
Sometimes a scream is better than a thesis.
Of no mortal say, 'That man is happy,' till vexed by no grievous ill he pass Life's goal.