【问题标题】:How do you do transition effects using the Frame control in WPF?如何使用 WPF 中的 Frame 控件进行过渡效果?
【发布时间】:2010-01-25 19:48:19
【问题描述】:

我认为这很容易,但我想不会。

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

似乎在互联网上的任何地方都找不到这个。

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

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

【问题讨论】:

  • 感谢您发布更新!
  • 如果您正在寻找水平幻灯片,其中每个帧并排并左右移动,您将很难使用导航源。它会想要将第 1 页向左转换,然后当它完成后,它会将第 2 页从右向左转换。

标签: c# wpf user-interface frame


【解决方案1】:

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

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

希望这会有所帮助,问候

【讨论】:

  • 当对页面内的元素使用“重”样式时,动画会混乱。是否有任何最佳实践可以使其更快地工作? (比如在 GPU 上渲染它或在运行时截取屏幕截图并为图像设置动画而不是所有元素等......)
  • 工作但需要更改 if 条件。而不仅仅是内容,它必须是 frame.Content
  • 这个解决方案有效,我什至将它修改为使用margin 属性,但是有没有办法同时在两个页面上进行更改?例如,更改margin 将使页面滑动,因此同时将使一页滑出,下一页将滑入替换旧页面,我该怎么做?
【解决方案2】:

我的答案是 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);
            }

【讨论】:

    【解决方案3】:

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

    我知道您正在使用 WPF,并且在 WPF 或 WPF 工具包中不提供 TransitioningContentControl。但是,将此控件移植到 WPF 或至少制作一个执行类似操作的控件可能并不太难。浏览一下源代码,如果您有时间,它看起来可能是可行的,而且它是您可以在其他地方重复使用的控件类型。

    Silverlight 版本的 source code is here 和 Jesse Liberty 有一个 nice tutorial,它通过使用 Silverlight 中的控件进行演示。

    【讨论】:

    • 我确实遇到过那个方法,但不幸的是我没有时间移植代码。
    • 您应该从 jesse liberty 中删除该教程。我不知道会发生什么,但它现在没用了。
    • 所以TransitioningContentControl 提供了我想要的效果。我的公司已经购买了 Telerik WPF 控件,并且他们的库中提供了该控件。感谢该控件的建议!
    【解决方案4】:

    我搜索了一个 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 相当陌生,所以如果有任何可以改进这个答案的东西,请在下面发布

    【讨论】:

      【解决方案5】:

      我只是在框架内容的OpacityProperty 导航时应用了双重动画。

      private void Frame_Navigating(object sender, NavigatingCancelEventArgs e)
      {
           var fa = new DoubleAnimation(0, 1, TimeSpan.FromSeconds(0.3));
           (e.Content as Page).BeginAnimation(OpacityProperty, fa);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-22
        • 2015-01-10
        • 2014-09-19
        • 2020-12-12
        相关资源
        最近更新 更多