Click here to Skip to main content
15,888,401 members
Articles / Desktop Programming / WPF

Page Transition Control for WPF

Rate me:
Please Sign up or sign in to vote.
5.00/5 (6 votes)
19 May 2011CPOL1 min read 35.6K   14   8
Like the title says... a simple (very simple) page transition control for WPF

About the Control

I have a little side project that I am working on which has multiple pages of information that need to be displayed, and I wanted a slicker way to transition between pages (UserControls) than just popping them into and out of existence (bad for the eyes).

My desire to have better looking transitions led me to develop a very simple control library with several animations built in for more elegant page switches.

The following page transition types are currently included in this version of the control:

  • Fade
  • Slide
  • SlideAndFade
  • Grow
  • GrowAndFade
  • Flip
  • FlipAndFade
  • Spin
  • SpinAndFade

The control itself is very simple... it consists of a UserControl (PageTransition), which contains all of the translation logic. Inside this control, there are several animations in the UserControl.Resources tag, defining all of the available animations. There is also an enum (PageTransitionType) which is mapped as a DependencyProperty that defines which animations are available to the users of the control.

Using the Control

Using the PageTransition control is easy... you just drop the control onto your WPF window, which will look something like this:

XML
<pageTransitions:PageTransition Name="pageTransition" 
Margin="25" TransitionType="SlideAndFade" /> 

Don't forget to add the namespace in your window/control declaration!

At this point, you can make a page change by doing something like this in your code-behind:

C#
NewPage newPage = new NewPage();
pageTransition.ShowPage(newPage);

So, that's about it... pretty simple, right?

Samples

Following are some examples of the animations I am doing in this sample:

XML
<!-- Grow and Fade -->
<Storyboard x:Key="GrowAndFadeIn" >
    <DoubleAnimation Storyboard.TargetProperty="(RenderTransform).
    (TransformGroup.Children)[0].(ScaleTransform.ScaleX)" 
    From="0" To="1" Duration="0:0:.75" 
    DecelerationRatio=".9" />
    <DoubleAnimation Storyboard.TargetProperty="(RenderTransform).
    (TransformGroup.Children)[0].(ScaleTransform.ScaleY)" 
    From="0" To="1" Duration="0:0:.75" 
    DecelerationRatio=".9" />
    <DoubleAnimation Duration="0:0:.25" 
    Storyboard.TargetProperty="Opacity" From="0" To="1" />
</Storyboard>

<Storyboard x:Key="GrowAndFadeOut">
    <DoubleAnimation Storyboard.TargetProperty="(RenderTransform).
    (TransformGroup.Children)[0].(ScaleTransform.ScaleX)" 
    To="0" Duration="0:0:.75" AccelerationRatio=".9" />
    <DoubleAnimation Storyboard.TargetProperty="(RenderTransform).
    (TransformGroup.Children)[0].(ScaleTransform.ScaleY)" 
    To="0" Duration="0:0:.75" AccelerationRatio=".9" />
    <DoubleAnimation Duration="0:0:.75" 
    Storyboard.TargetProperty="Opacity" To="0" />
</Storyboard>
XML
<!-- Spin -->
<Storyboard x:Key="SpinIn" >
    <DoubleAnimation Storyboard.TargetProperty="(RenderTransform).
    (TransformGroup.Children)[2].(RotateTransform.Angle)" 
    From="-360" To="0" Duration="0:0:.75" DecelerationRatio=".9" />
    <DoubleAnimation Storyboard.TargetProperty="(RenderTransform).
    (TransformGroup.Children)[0].(ScaleTransform.ScaleX)" 
    From="0" To="1" Duration="0:0:.75" DecelerationRatio=".9" />
    <DoubleAnimation Storyboard.TargetProperty="(RenderTransform).
    (TransformGroup.Children)[0].(ScaleTransform.ScaleY)" 
    From="0" To="1" Duration="0:0:.75" DecelerationRatio=".9" />            
</Storyboard>

<Storyboard x:Key="SpinOut">
    <DoubleAnimation Storyboard.TargetProperty="(RenderTransform).
    (TransformGroup.Children)[2].(RotateTransform.Angle)" 
    To="360" Duration="0:0:.75" AccelerationRatio=".9" />
    <DoubleAnimation Storyboard.TargetProperty="(RenderTransform).
    (TransformGroup.Children)[0].(ScaleTransform.ScaleX)" 
    To="0" Duration="0:0:.75" AccelerationRatio=".9" />
    <DoubleAnimation Storyboard.TargetProperty="(RenderTransform).
    (TransformGroup.Children)[0].(ScaleTransform.ScaleY)" 
    To="0" Duration="0:0:.75" AccelerationRatio=".9" />
</Storyboard>

Here is what I am doing in the code-behind for the actual page transitions themselves. There were some funky issues that I encountered while trying to get the animations working, but everything is resolved now. Notice how I am using the enumeration to determine which animation to load.

C#
/// <summary>
/// Show a new page - this function starts a task to show the page and then returns right away
/// </summary>
public void ShowPage(UserControl newPage)
{            
    pages.Push(newPage);
    Task.Factory.StartNew(() => ShowNewPage());
}

/// <summary>
/// Actual function that unloads the old page (if any) and shows the new page.
/// </summary>
void ShowNewPage()
{
    Dispatcher.Invoke((Action)delegate 
        {
            if (contentPresenter.Content != null)
            {
                UserControl oldPage = contentPresenter.Content as UserControl;

                if (oldPage != null)
                {
                    oldPage.Loaded -= newPage_Loaded;
                    UnloadPage(oldPage);
                }
            }
            else
            {
                ShowNextPage();
            }
                    
        });
}

/// <summary>
/// Pops the next page off of the stack, maps the loaded event, 
/// and then sets the content of the ContentControl to the new page.
/// </summary>
void ShowNextPage()
{
    UserControl newPage = pages.Pop();
    newPage.Loaded += newPage_Loaded;
    contentPresenter.Content = newPage;
}

/// <summary>
/// Starts the animation unloading the existing page - 
/// note the completed event being mapped.
/// </summary>
void UnloadPage(UserControl page)
{
    Storyboard hidePage = (Resources[string.Format("{0}Out", 
    TransitionType.ToString())] as Storyboard).Clone();
    hidePage.Completed += hidePage_Completed;
    hidePage.Begin(contentPresenter);
}

/// <summary>
/// Once the new page is loaded into the ContentControl, the animation is started.
/// </summary>
void newPage_Loaded(object sender, RoutedEventArgs e)
{
    Storyboard showNewPage = Resources[string.Format
    ("{0}In", TransitionType.ToString())] as Storyboard;
    showNewPage.Begin(contentPresenter);
    CurrentPage = sender as UserControl;
}        

/// <summary>
/// Loads the next page after the unload of the previous page
/// </summary>
void hidePage_Completed(object sender, EventArgs e)
{
    contentPresenter.Content = null;
    ShowNextPage();
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United States United States
Check out my technical blog here: The Fyslexic Duck. You can find most of what I've put on CodeProject there, plus some additional technical articles.

Comments and Discussions

 
QuestionProblem with a large listbox with cusom Items Pin
Member 801729412-Dec-13 4:15
Member 801729412-Dec-13 4:15 
SuggestionThanks for a Great Tool & Include my suggestion Pin
Jagadeeswaran Natarajan24-Nov-13 18:15
professionalJagadeeswaran Natarajan24-Nov-13 18:15 
QuestionTransition between windows Pin
AHKhalid20-May-13 5:12
AHKhalid20-May-13 5:12 
AnswerRe: Transition between windows Pin
Jagadeeswaran Natarajan24-Nov-13 18:01
professionalJagadeeswaran Natarajan24-Nov-13 18:01 
Questionhelp! Pin
Member 95703715-May-13 17:33
Member 95703715-May-13 17:33 
AnswerRe: help! Pin
Jagadeeswaran Natarajan22-Nov-13 23:35
professionalJagadeeswaran Natarajan22-Nov-13 23:35 
GeneralGreat Work Pin
2befrank10-Feb-13 21:45
2befrank10-Feb-13 21:45 
GeneralRe: Great Work Pin
Aron Weiler11-Feb-13 14:02
Aron Weiler11-Feb-13 14:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.