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:
<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:
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:
<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>
<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.
public void ShowPage(UserControl newPage)
{
pages.Push(newPage);
Task.Factory.StartNew(() => ShowNewPage());
}
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();
}
});
}
void ShowNextPage()
{
UserControl newPage = pages.Pop();
newPage.Loaded += newPage_Loaded;
contentPresenter.Content = newPage;
}
void UnloadPage(UserControl page)
{
Storyboard hidePage = (Resources[string.Format("{0}Out",
TransitionType.ToString())] as Storyboard).Clone();
hidePage.Completed += hidePage_Completed;
hidePage.Begin(contentPresenter);
}
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;
}
void hidePage_Completed(object sender, EventArgs e)
{
contentPresenter.Content = null;
ShowNextPage();
}