如何在WPF中使用Frame控件进行过渡效果?

时间:2010-01-25 19:48:19

标签: c# wpf user-interface frame

我认为这很容易,但我猜不是。

我有两页加载到我的帧控件中。我希望能够拥有 从一个页面到下一个页面的漂亮幻灯片效果或只是一个简单的淡入效果。

似乎无法在互联网上的任何地方找到它。

更新1 接受的答案很好,但我在这里找到了更好的答案。 http://www.japf.fr/2008/07/8/comment-page-1/

更新2 如果你能相信它,我找到了更好的解决方案。
http://fluidkit.codeplex.com/

4 个答案:

答案 0 :(得分:19)

此处讨论的问题类似:Transition Fade Animation When Navigating To Page使用此处描述的技术,您可以在每次导航新页面时滑动\移动帧控件。像这样的Smth:

XAML:

...
<Frame Name = "frame" Navigating="frame_Navigating">
...

代码:

...
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);
        });
}
...

希望这有帮助,尊重

答案 1 :(得分:8)

我的答案是serge_gebunko给出的答案的改进版本 它为您提供滑动左右效果

<强> 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);
            }

答案 2 :(得分:1)

这可能不是最佳答案,但它可能对您有所帮助,或者至少可以给您一些想法。在Silverlight中,我通过使用Silverlight Toolkit中的TransitioningContentControl在页面之间实现了这种类型的滑动过渡效果。它是一个内容控件,它基本上允许您在可视状态下定义自定义故事板,以便在内容更改时在旧内容和新内容之间进行转换。如果您不想花时间定义自定义故事板,它还包括一些默认(淡入淡出/向上/向下)过渡。

我意识到您正在使用WPF,而且转换内容控件在WPF或WPF工具包中不可用。但是,将此控制移植到WPF或至少使一个类似的东西可能并不太难。如果您有时间,看起来它可能是可行的,它可能是可以在其他地方重复使用的控制类型。

Silverlight版本的source code is here和Jesse Liberty有nice tutorial,它使用Silverlight中的控件。

答案 3 :(得分:0)

我搜索了mvvm友好的答案,但没有找到任何答案,因此我使用附加属性制作了自己的答案:

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;
    }
}

用法:

 <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>

对于mvvm来说还很新,所以如果有什么可以改善此答案的内容,请在下面将其发布