Simplifying Page Transitions in Windows Phone 7 Silverlight Applications

4/26/2010 1:33:00 PM

Screencast of this article is available:

Source code of sample application download here.

If you have played around with Silverlight on Windows Phone 7, one thing you may have tried to figure out is how to add nice transitions between different pages of your application.  By default, Windows Phone page transitions really aren’t transitions at all.  The new PhoneNavigationPage is just popped into the root PhoneNavigationFrame.  Effective, yes. Cool, certainly not.  Face it, modern mobile applications need to not only be functional, but also stylish.  Simple “snap” transitions just don’t cut it.

The most common solution to this problem is to use brute force and manage the transitions yourself.  You commonly see a “pattern” used in WP7 apps where events in your current page launch a Storyboard animation.  When that animation is complete, the actual navigation to the new page is invoked and the new page then runs its own Storyboard once it is loaded.  It looks something like this…

// CURRENT PAGE
       private void CurrentPage_Click(object sender, EventArgs e)
       {
           SomeStoryboard.Completed += new EventHandler(SomeStoryboard_Completed);
           SomeStoryboard.Begin();                       
       }

       void SomeStoryboard_Completed(object sender, EventArgs e)
       {
           NavigationService.Navigate(new Uri("/Favorites", UriKind.Relative)); 
       }

// NEWPAGE
protected override void OnNavigatedTo(Microsoft.Phone.Navigation.PhoneNavigationEventArgs e)
{
    base.OnNavigatedTo(e);

    SomeNewStoryboard.Begin();
}

It’s a straightforward solution, and if your app only has a few pages, it works just fine.  If you have lots of pages in your application, however, it becomes quite tedious and hard to maintain.

A better solution can be found by turning to the Silverlight Toolkit.  The great thing about having Silverlight on WP7 is that you can leverage many existing Silverlight assets.  In this case, we will leverage the TransitioningContentControl from the Toolkit.  The TransitioningContentControl was created to solve the same problem we are facing for traditional navigation-based Silverlight application.

To get started, download the Silverlight Toolkit from CodePlex. Once installed, you will need to add the System.Windows.Controls.Layout.Toolkit assembly to your WP7 project.

If you are not familiar with the TransitioningContentControl, its a fairly simple control.  The TCC is comprised of two ContentPresenters – current and previous.  When you update the Content property of the TCC, it will take the content of the CurrentContentPresenter (if present) and move it to the PreviousContentPresenter.  The new content is loaded into the CurrentContentPresenter.  The TCC, however, manages the visibility of the previous and Current ContentPresenters so that the “old” content is visible and the “new” content is hidden.  It then uses a Storyboard that is defined as part of the TCC’s VisualStateManager to transition from the “old” content to the “new” content.  If you are not familiar with Storyboards, the Visual State Manager, or other designer-type topics, have no fear.  The TCC comes with a set of standard transitions that you can use out of the box.

Getting the TCC to work with our WP7 app is a simple process.  First, we need to modify the ControlTemplate for our PhoneNavigationFrame to use the TCC.  By doing so, we automatically enable transitions between any PhoneNavigationPages we add to our app.  To change the PhoneNavigationFrame, open the App.xaml file.  First, add a couple of namespaces to our xaml:

    xmlns:layout="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
    xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"

Now, modify the PhoneNavigationFrame as shown below:

        <phoneNavigation:PhoneApplicationFrame x:Name="RootFrame" Source="/MainPage.xaml">
            <phoneNavigation:PhoneApplicationFrame.Template>
                <ControlTemplate>
                    <layout:TransitioningContentControl Content="{TemplateBinding Content}" Style="{StaticResource TransitioningStyle}"/>
                </ControlTemplate>
            </phoneNavigation:PhoneApplicationFrame.Template>
        </phoneNavigation:PhoneApplicationFrame>

 

The TCC has its Style property set to a StaticResource.  This Style provides the default transitions and is also where you would add your own VisualStates and Storyboards if you would like to add custom transitions.  This Style can be found in the Silverlight Toolkit in the TCC Sample Application, or you can get it from the sample WP7 application linked to this article.  The Style is long so I won’t show the entire thing here, but the first parts of the Style are below to give an idea of what the Style contains and how it is used by the TCC.

  <Style x:Key="TransitioningStyle" TargetType="layout:TransitioningContentControl">
            <Setter Property="Transition" Value="DefaultTransition" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="layout:TransitioningContentControl">
                        <Border Background="{TemplateBinding Background}" 
                                BorderBrush="{TemplateBinding BorderBrush}" 
                                BorderThickness="{TemplateBinding BorderThickness}" 
                                CornerRadius="2">
                            <vsm:VisualStateManager.VisualStateGroups>
                                <vsm:VisualStateGroup x:Name="PresentationStates">
                                    <vsm:VisualState x:Name="DefaultTransition">
                                        <Storyboard>
                                            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
                                                                           Storyboard.TargetName="CurrentContentPresentationSite" 
                                                                           Storyboard.TargetProperty="(UIElement.Opacity)">
                                                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0" />
                                                <SplineDoubleKeyFrame KeyTime="00:00:02.300" Value="1" />
                                            </DoubleAnimationUsingKeyFrames>
                                            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
                                                                           Storyboard.TargetName="PreviousContentPresentationSite" 
                                                                           Storyboard.TargetProperty="(UIElement.Opacity)">
                                                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1" />
                                                <SplineDoubleKeyFrame KeyTime="00:00:02.300" Value="0" />
                                            </DoubleAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </vsm:VisualState>
                                    <vsm:VisualState x:Name="Normal">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" 
                                                                           Storyboard.TargetName="PreviousContentPresentationSite" 
                                                                           Storyboard.TargetProperty="(UIElement.Visibility)">
                                                <DiscreteObjectKeyFrame KeyTime="00:00:00">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>
                                                            Collapsed
                                                        </Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </vsm:VisualState>

 

I won’t break the Style down in detail, but I’ll point a couple of highlights.  First, the Transition property is set to the VisualState that you would like to use as the transition between pages.  Every transition will use this VisualState storyboard.  The DefaultTransition VisualState is an example of how Storyboards are constructed for use in a transition.  As you can see, each Storyboard must target both the CurrentContentPresentationSite and the PreviousContentPresentationSite (these are the ContentPresenters discussed earlier).  You can target more than one property if you like.  Below is a custom transition that can be found in my sample app that both rotates the projection plane and the opacity of the ContentPresenters.

<vsm:VisualState x:Name="SwingTransition">
                                        <Storyboard>
                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" 
                                                                           Storyboard.TargetName="PreviousContentPresentationSite">
                                                <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                                                <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="90"/>
                                            </DoubleAnimationUsingKeyFrames>
                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" 
                                                                           Storyboard.TargetName="PreviousContentPresentationSite">
                                                <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
                                                <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0"/>
                                            </DoubleAnimationUsingKeyFrames>
                                            <DoubleAnimation Duration="0" To="0" 
                                                             Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.CenterOfRotationX)" 
                                                             Storyboard.TargetName="PreviousContentPresentationSite" />
                                            <DoubleAnimation Duration="0" To="1" 
                                                             Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.CenterOfRotationX)" 
                                                             Storyboard.TargetName="CurrentContentPresentationSite" />
                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" 
                                                                           Storyboard.TargetName="CurrentContentPresentationSite">
                                                <EasingDoubleKeyFrame KeyTime="0" Value="90"/>
                                                <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0"/>
                                            </DoubleAnimationUsingKeyFrames>
                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" 
                                                                           Storyboard.TargetName="CurrentContentPresentationSite">
                                                <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                                                <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="1"/>
                                            </DoubleAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </vsm:VisualState>

 

That’s it.  You now have transitions any time you Navigate to a new PhoneNavigationPage

Tags:

Screencasts | Windows Phone

Comments

5/6/2010 12:28:27 AM

Thanks for the helpful information. Is there a way to disable (or change) the type of transition in different pages? Basically I need to show different transitions for different pages.

thanks.

Mohammed United States

5/7/2010 5:59:25 AM

Thanks! I'm having a problem compiling the code in App.xaml.cs:

FindAZip\App.xaml.cs(41,35): error CS0117: 'System.Windows.Navigation.NavigationService' does not contain a definition for 'TopLevelNavigationService'

Here's the code that failed:

NavigationService.TopLevelNavigationService.Navigate(new Uri("/Error", UriKind.Relative));

Did something change between the CTP and now?

Hugh Williams United States

5/12/2010 9:16:16 AM

There was a change in the April Refresh.  You just need to grab the Root Visual from Application.Current and grab the navigation service from there.

JAB United States

5/12/2010 9:16:50 AM

I am looking at how to have different transitions on a per page basis.  Haven't had time to play with the TransitioningContentControl to make that happen.

JAB United States

Comments are closed

Powered by BlogEngine.NET 1.6.0.0
Theme by Mads Kristensen

About the author

Jeff Brand Jeff Brand

This is the personal web site of Jeff Brand, self-proclaimed .NET Sex Symbol and All-Around Good guy. Content from my presentations, blog, and links to other useful .NET information can all be found here.

E-mail me Send mail


Calendar

<<  April 2014  >>
MoTuWeThFrSaSu
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar

My Twitter Updates

XBOX
Live

Recent comments

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2014

Sign in