I thought this would be easy but I guess not.
I have 2 pages that load in my frame control. I want to be able to either have
a nice slide effect from one page to the next or just a simple fade-In effect.
Can't seem to find this anywhere on the internets.
Update 1
The accepted answer is good, but I found an even better one here.
http://www.japf.fr/2008/07/8/comment-page-1/
Update 2
If you can believe it I found an even better solution.
http://fluidkit.codeplex.com/
There is a similar problem discussed here: Transition Fade Animation When Navigating To Page Using the technique described there you can slide\move your frame control each time a new page is navigated. Smth like this:
xaml:
...
<Frame Name = "frame" Navigating="frame_Navigating">
...
code:
...
private bool _allowDirectNavigation = false;
private NavigatingCancelEventArgs _navArgs = null;
private Duration _duration = new Duration(TimeSpan.FromSeconds(1));
private double _oldHeight = 0;
private void frame_Navigating(object sender, NavigatingCancelEventArgs e)
{
if (Content!=null && !_allowDirectNavigation)
{
e.Cancel = true;
_navArgs = e;
_oldHeight = frame.ActualHeight;
DoubleAnimation animation0 = new DoubleAnimation();
animation0.From = frame.ActualHeight;
animation0.To = 0;
animation0.Duration = _duration;
animation0.Completed += SlideCompleted;
frame.BeginAnimation(HeightProperty, animation0);
}
_allowDirectNavigation = false;
}
private void SlideCompleted(object sender, EventArgs e)
{
_allowDirectNavigation = true;
switch (_navArgs.NavigationMode)
{
case NavigationMode.New:
if (_navArgs.Uri == null)
frame.Navigate(_navArgs.Content);
else
frame.Navigate(_navArgs.Uri);
break;
case NavigationMode.Back:
frame.GoBack();
break;
case NavigationMode.Forward:
frame.GoForward();
break;
case NavigationMode.Refresh:
frame.Refresh();
break;
}
Dispatcher.BeginInvoke(DispatcherPriority.Loaded,
(ThreadStart)delegate()
{
DoubleAnimation animation0 = new DoubleAnimation();
animation0.From = 0;
animation0.To = _oldHeight;
animation0.Duration = _duration;
frame.BeginAnimation(HeightProperty, animation0);
});
}
...
hope this helps, regards
My answer is the improved version of the answer given by serge_gebunko.
It gives you the Sliding left and right effect.
XAML
...
<Frame Name = "MainFrame" Navigating="MainFrame_OnNavigating">
...
C#
private void MainFrame_OnNavigating(object sender, NavigatingCancelEventArgs e) {
var ta = new ThicknessAnimation();
ta.Duration = TimeSpan.FromSeconds(0.3);
ta.DecelerationRatio = 0.7;
ta.To = new Thickness(0 , 0 , 0 , 0);
if (e.NavigationMode == NavigationMode.New) {
ta.From = new Thickness(500, 0, 0, 0);
}
else if (e.NavigationMode == NavigationMode.Back) {
ta.From = new Thickness(0 , 0 , 500 , 0);
}
(e.Content as Page).BeginAnimation(MarginProperty , ta);
}
This probably isn't the best answer, but it maybe helpful to you or at least give you some ideas. In Silverlight I have achieved that type of sliding transition effect between pages by using the TransitioningContentControl from the Silverlight Toolkit. It is a content control which basically lets you define a custom storyboard in a visual state for a transition between the old and new content whenever the content changes. It also includes some default (fade/up/down) transitions if you don't want to take the time to define a custom storyboard.
I realize that you are working with WPF and that the TransitioningContentControl is not available in WPF or in the WPF Toolkit. However, it may not be too difficult to port this control over to WPF or at least make one that does something similar. Glancing over the source it looks like it may be doable if you have the time and it is the type of control you may reuse in other places.
The source code is here for the Silverlight version and Jesse Liberty has a nice tutorial which walks through using the control in Silverlight.
i searched for a mvvm friendly answer and i didn't find any so i made my own using an attached property:
public class FrameAnimator : DependencyObject
{
public static readonly DependencyProperty FrameNextNavigationStotryboardProperty = DependencyProperty.RegisterAttached("FrameNextNavigationStotryboard", typeof(Storyboard), typeof(FrameAnimator), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure, FrameNextNavigationStotryboardProprtyChanged));
private static void FrameNextNavigationStotryboardProprtyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Frame)
{
Storyboard st = GetFrameNextNavigationStotryboard(d);
if (st != null)
{
(d as Frame).Navigating += (sm, ar) =>
{
if (ar.NavigationMode != System.Windows.Navigation.NavigationMode.Back)
{
st.Begin((d as Frame));
}
};
}
}
}
public static void SetFrameNextNavigationStotryboard(DependencyObject control, Storyboard st)
{
control.SetValue(FrameNextNavigationStotryboardProperty, st);
}
public static Storyboard GetFrameNextNavigationStotryboard(DependencyObject control)
{
var val = control.GetValue(FrameNextNavigationStotryboardProperty);
if (val is Storyboard)
return (Storyboard)val;
return null;
}
/// <summary>
/// /////////////////////////////////////////////////////////////////////
/// </summary>
public static readonly DependencyProperty FrameBackNavigationStotryboardProperty = DependencyProperty.RegisterAttached("FrameBackNavigationStotryboard", typeof(Storyboard), typeof(FrameAnimator), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure, FrameBackNavigationStotryboardProprtyChanged));
private static void FrameBackNavigationStotryboardProprtyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Frame)
{
Storyboard st = GetFrameBackNavigationStotryboard(d);
if (st != null)
{
(d as Frame).Navigating += (sm, ar) =>
{
if (ar.NavigationMode == System.Windows.Navigation.NavigationMode.Back)
{
st.Begin((d as Frame));
}
};
}
}
}
public static void SetFrameBackNavigationStotryboard(DependencyObject control, Storyboard st)
{
control.SetValue(FrameBackNavigationStotryboardProperty, st);
}
public static Storyboard GetFrameBackNavigationStotryboard(DependencyObject control)
{
var val = control.GetValue(FrameBackNavigationStotryboardProperty);
if (val is Storyboard)
return (Storyboard)val;
return null;
}
}
Usage :
<Window x:Class="sqlTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:fr="clr-namespace:YourNameSpace;assembly=YourNameSpace">
<Window.Resources>
<system:Double x:Key="TValue">
1000
</system:Double>
<system:Double x:Key="NTValue">
-1000
</system:Double>
<Storyboard x:Key="NavNextAnim">
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.800"/>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)" To="0" From="{StaticResource ResourceKey=TValue}" Duration="0:0:0.3"/>
</Storyboard>
<Storyboard x:Key="NavBackAnim">
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.800"/>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)" To="0" From="{StaticResource ResourceKey=NTValue}" Duration="0:0:0.3"/>
</Storyboard>
</Window.Resources>
<Frame
fr:FrameAnimator.FrameNextNavigationStotryboard="{StaticResource ResourceKey=NavNextAnim}"
fr:FrameAnimator.FrameBackNavigationStotryboard="{StaticResource ResourceKey=NavBackAnim}">
<Frame.RenderTransform>
<TranslateTransform/>
</Frame.RenderTransform>
</Frame>
</Window>
Am fairly new to mvvm so if there is any thing that can improve this answer please post it below