Как вы делаете эффекты перехода, используя элемент управления Frame в WPF?

Я думал, что это будет легко, но я думаю, что нет.

У меня есть 2 страницы, которые загружаются в моем элементе управления кадром. Я хочу иметь возможность иметь хороший эффект слайда с одной страницы на другую или просто простой эффект постепенного появления.

Кажется, нигде в инете этого не найти.

Обновление 1 Принятый ответ хорош, но здесь я нашел еще лучший. http://www.japf.fr/2008/07/8/comment-page-1/

Обновление 2 Если вы можете в это поверить, я нашел еще лучшее решение.
http://fluidkit.codeplex.com/


person Donny V.    schedule 25.01.2010    source источник
comment
Спасибо за публикацию обновлений!   -  person Gishu    schedule 06.09.2011
comment
Если вы ищете горизонтальный слайд, где каждый кадр расположен рядом и перемещается вместе влево и вправо, у вас будут проблемы с источником навигации. Он захочет перевести страницу 1 влево, а затем, когда это будет сделано, он переместит страницу 2 справа налево.   -  person The Muffin Man    schedule 23.02.2015


Ответы (4)


Здесь обсуждается аналогичная проблема: >Анимация плавного перехода при переходе на страницу Используя описанную здесь технику, вы можете сдвигать\перемещать элемент управления кадром каждый раз при переходе на новую страницу. Что-то вроде этого:

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

надеюсь, это поможет, с уважением

person serge_gubenko    schedule 26.01.2010
comment
При использовании «тяжелого» стиля для элементов внутри страницы анимация загромождается. Существуют ли какие-либо рекомендации, чтобы заставить его работать быстрее? (Например, визуализировать его на графическом процессоре или сделать снимок экрана во время выполнения и анимировать изображение вместо всех элементов и т. д.) - person Uri Abramson; 11.05.2014
comment
Работает, но нужно изменить условие if. а не только Content, это должен быть frame.Content - person Anup Sharma; 06.10.2016
comment
это решение сработало, я даже изменил его для работы со свойством margin, но можно ли в любом случае внести изменения на двух страницах одновременно? например, изменение margin приведет к тому, что страницы будут скользить, поэтому одновременно одна страница будет скользить, а следующая страница будет скользить вместо старой, как я могу это сделать? - person ibr; 07.01.2019

Мой ответ — это улучшенная версия ответа, данного serge_gebunko.
Он дает вам эффект скольжения влево и вправо.

XAML

...
<Frame Name = "MainFrame" Navigating="MainFrame_OnNavigating">
...

С#

 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);
            }
person Wong Jia Hau    schedule 10.04.2017

Это, вероятно, не лучший ответ, но он может быть вам полезен или, по крайней мере, дать вам некоторые идеи. В Silverlight я добился такого эффекта скользящего перехода между страницами с помощью TransitioningContentControl из Silverlight Toolkit. Это элемент управления содержимым, который в основном позволяет вам определить пользовательскую раскадровку в визуальном состоянии для перехода между старым и новым содержимым при каждом изменении содержимого. Он также включает в себя некоторые переходы по умолчанию (исчезновение/вверх/вниз), если вы не хотите тратить время на определение пользовательской раскадровки.

Я понимаю, что вы работаете с WPF и что TransitioningContentControl недоступен в WPF или в наборе инструментов WPF. Тем не менее, может быть не слишком сложно перенести этот элемент управления в WPF или, по крайней мере, сделать что-то подобное. Глядя на исходный код, кажется, что это может быть выполнимо, если у вас есть время, и это тип управления, который вы можете повторно использовать в других местах.

исходный код версии Silverlight находится здесь, а у Джесси Либерти есть хорошее руководство который проходит через элемент управления в Silverlight.

person Dan Auclair    schedule 26.01.2010
comment
Я столкнулся с этим методом, но, к сожалению, у меня нет времени портировать код. - person Donny V.; 26.01.2010
comment
Вы должны удалить учебник из Джесси Либерти. Я не знаю, что происходит, но теперь это бесполезно. - person Syaiful Nizam Yahya; 20.02.2014
comment
Итак, TransitioningContentControl обеспечивает желаемый эффект, который я хотел. Моя компания уже приобрела элементы управления Telerik WPF, и в их библиотеке есть этот элемент управления. Спасибо за предложение этого контроля! - person The Muffin Man; 23.02.2015

я искал дружественный ответ 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, поэтому, если есть что-то, что может улучшить этот ответ, опубликуйте его ниже.

person Community    schedule 13.01.2020