locked
MVVM, entrance and exit animations of custom dialogs

    Question

  • Hi All,

    I am somewhat new to MVVM. I'm trying to create an app using as much MVVM as I possibly can.

    I want dialogs that enter and exit the screen nicely when the user clicks a button (think of the settings in the charm bar for what I mean). Sometimes, I want to use custom animations (transitions may not be good enough). In the past, I've used a bool in my ViewModel that the control binds to it's visibility by using a converter. This works well, but does not provide entrance and exit type animations.

    Looking online, it seems that Triggers is the preferred way to do this on WPF, but alas that is not available for Windows Store apps.

    The only other solution I can think of is to create some form of Interface/BaseClass that has an EntranceAnimation and ExitAnimation Storyboard type properties that the specific controls can then implement. I will then have to set these values in the CodeBehind for each of the controls that I want to animate in and out. The Exit/Entrance animations could then be used and I could attach a function to the OnCompleted callback to remove it or make it's Visibility Collapsed.

    Any concrete ideas on how to best go about this (preferably some sample code).

    Thanks in Advance,

    Tomas Hofmann

    Wednesday, July 9, 2014 12:50 AM

Answers

  • I have another very generic way to deal with it using my StoryboardPlayer utility class

    using System;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Media.Animation;
    
    namespace Kaushik.Utilities
    {
        public class StoryboardPlayer : FrameworkElement
        {
            #region Dependency Properties
            public static readonly DependencyProperty TriggerProperty =
                DependencyProperty.Register("Trigger", typeof(object), typeof(StoryboardPlayer), new PropertyMetadata(null, onTriggerChanged));
    
            public static readonly DependencyProperty MyPropertyProperty =
                DependencyProperty.Register("Storyboard", typeof(Storyboard), typeof(StoryboardPlayer), new PropertyMetadata(null));
            #endregion Dependency Properties
    
            #region Properties
            public object Trigger
            {
                get { return (object)GetValue(TriggerProperty); }
                set { SetValue(TriggerProperty, value); }
            }
    
            public Storyboard Storyboard
            {
                get { return (Storyboard)GetValue(MyPropertyProperty); }
                set { SetValue(MyPropertyProperty, value); }
            }
            #endregion Properties
    
            #region Constructor
            public StoryboardPlayer()
            {
                this.Visibility = Visibility.Collapsed;
            }
            #endregion Constructor
    
            #region Trigger value change handler
            private static void onTriggerChanged(DependencyObject source, DependencyPropertyChangedEventArgs changeArguments)
            {
                StoryboardPlayer storyboardPlayer = source as StoryboardPlayer;
    
                if (storyboardPlayer != null
                    && storyboardPlayer.Trigger != null
                    && storyboardPlayer.Storyboard != null)
                {
                    Type triggerType = storyboardPlayer.Trigger.GetType();
    
                    switch (triggerType.ToString())
                    {
                        case "System.Boolean":
                            if ((Boolean)storyboardPlayer.Trigger)
                            {
                                storyboardPlayer.Storyboard.Begin();
                            }
                            else
                            {
                                storyboardPlayer.Storyboard.Stop();
                            }
                            break;
                        //Implement other types that need to be supported or use a Value Converter in binding to make it Boolean
                    }
                }
            }
            #endregion Trigger value change handler
        }
    }

    This how you can use it in XAML

    <Page
        x:Class="MsdnSample22072014.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:MsdnSample22072014"
        xmlns:k="using:Kaushik.Utilities"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
        <Page.Resources>
            <Storyboard x:Name="SampleStoryboard">
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="Button1">
                    <EasingDoubleKeyFrame KeyTime="0" Value="814.925"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="405.97"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="361.194"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="Button1">
                    <EasingDoubleKeyFrame KeyTime="0" Value="395.522"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="308.955"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="628.358"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="Button2">
                    <EasingDoubleKeyFrame KeyTime="0" Value="300"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="694.03"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="626.866"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:7" Value="594.03"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="Button2">
                    <EasingDoubleKeyFrame KeyTime="0" Value="486.567"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="179.104"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="544.776"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:7" Value="141.791"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="Button5">
                    <EasingDoubleKeyFrame KeyTime="0" Value="443.284"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="119.403"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="753.731"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:7" Value="570.149"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="Button5">
                    <EasingDoubleKeyFrame KeyTime="0" Value="5.97"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="223.88"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="289.552"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:7" Value="279.104"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="Button4">
                    <EasingDoubleKeyFrame KeyTime="0" Value="505.97"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="540.298"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="119.402"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="Button4">
                    <EasingDoubleKeyFrame KeyTime="0" Value="-28.358"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="394.03"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="441.791"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="Button3">
                    <EasingDoubleKeyFrame KeyTime="0" Value="419.403"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="11.94"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="888.059"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:7" Value="752.238"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="Button3">
                    <EasingDoubleKeyFrame KeyTime="0" Value="268.657"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="-53.731"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="261.194"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:7" Value="392.537"/>
                </DoubleAnimationUsingKeyFrames>
            </Storyboard>
        </Page.Resources>
        <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <Button x:Name="Button1" Content="Sample 1" RenderTransformOrigin="0.5,0.5">
                <Button.RenderTransform>
                    <CompositeTransform/>
                </Button.RenderTransform>
            </Button>
            <Button x:Name="Button2" Content="Sample 2" RenderTransformOrigin="0.5,0.5">
                <Button.RenderTransform>
                    <CompositeTransform/>
                </Button.RenderTransform>
            </Button>
            <Button x:Name="Button3" Content="Sample 3" RenderTransformOrigin="0.5,0.5">
                <Button.RenderTransform>
                    <CompositeTransform/>
                </Button.RenderTransform>
            </Button>
            <Button x:Name="Button4" Content="Sample 4" RenderTransformOrigin="0.5,0.5">
                <Button.RenderTransform>
                    <CompositeTransform/>
                </Button.RenderTransform>
            </Button>
            <Button x:Name="Button5" Content="Sample 5" RenderTransformOrigin="0.5,0.5">
                <Button.RenderTransform>
                    <CompositeTransform/>
                </Button.RenderTransform>
            </Button>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Use me to start and stop animation!" Margin="5" FontSize="24"/>
                <CheckBox x:Name="control" Margin="5"/>
            </StackPanel>
            <k:StoryboardPlayer Trigger="{Binding ElementName=control, Path=IsChecked}" Storyboard="{StaticResource SampleStoryboard}"/>
        </StackPanel>
    </Page>

    You can implement my player class where you support multiple story boards and have conditional logic to play one of them.

    I am just posting this as an alternate.


    -- Vishal Kaushik --

    Please 'Mark as Answer' if my post answers your question and 'Vote as Helpful' if it helps you. Happy Coding!!!



    • Edited by Vishal Kaushik Tuesday, July 22, 2014 6:15 PM
    • Marked as answer by T Hofmann Wednesday, July 23, 2014 3:52 PM
    Tuesday, July 22, 2014 6:02 PM

All replies

  • Hi Tomas,

    For better understand how MVVM works in Windows Store App, I would suggest you go though documentation: Use the Model-View-ViewModel (MVVM) pattern

    Hilo is a good sample for implement MVVM in Windows Store App, which is also available online: Using the MVVM pattern

    To play the animation by Trigger is a typical way in WPF, what we do in Store App is to use Template, for instance a Button clicked, to play the animation we have to modify the Button Template: Button styles and templates, the animation is fired for certain visual state for instance click button is Pressed.

                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                                       Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonPressedBackgroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                                       Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonPressedForegroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Friday, July 11, 2014 8:02 AM
    Moderator
  • Thanks for the answer James,

    It seems a little odd to me that a button contains animations for a completely different control inside it's state. I can see why it works, but it's a little odd to me.

    I ended up constructing a Class derived from ContentControl, with an IsOpen dependency Property, as well as an EntranceAnimation and ExitAnimation dependency properties. I can then bind the Animations in it (two way) to Animations I've specified in Xaml, and the IsOpen is bound to a bool in the ViewModel.

    e.g.:

                <Grid.Resources>
                    <Storyboard x:Name="TextSearchBarEntranceAnimation" common:AnimationCompletedCommand.Command="{Binding TextSearchBarHasEnteredCommand, Mode=TwoWay}">
                        <DoubleAnimation Duration="0:0:0.350" Storyboard.TargetName="TextSearchBarTransformation" Storyboard.TargetProperty="Y" To="0">
                            <DoubleAnimation.EasingFunction>
                                <QuadraticEase EasingMode="EaseOut"/>
                            </DoubleAnimation.EasingFunction>
                        </DoubleAnimation>
                    </Storyboard>
                    <Storyboard x:Name="TextSearchBarExitAnimation">
                        <DoubleAnimation Duration="0:0:0.267" Storyboard.TargetName="TextSearchBarTransformation" Storyboard.TargetProperty="Y" To="100">
                            <DoubleAnimation.EasingFunction>
                                <QuadraticEase EasingMode="EaseIn"/>
                            </DoubleAnimation.EasingFunction>
                        </DoubleAnimation>
                    </Storyboard>
                </Grid.Resources>
    
                <controls:EntranceAnimationContentControl HorizontalAlignment="Stretch" VerticalAlignment="Bottom" IsOpen="{Binding IsFindTextOpen}" 
                                                          EntranceAnimation="{Binding ElementName=TextSearchBarEntranceAnimation, Mode=TwoWay}"
                                                          ExitAnimation="{Binding ElementName=TextSearchBarExitAnimation, Mode=TwoWay}"
                                                          Visibility="Collapsed">
                    <controls:EntranceAnimationContentControl.RenderTransform>
                        <TranslateTransform x:Name="TextSearchBarTransformation" Y="100"/>
                    </controls:EntranceAnimationContentControl.RenderTransform>
                    
                    <Border Height="88">
                        <controls:FindTextControl DataContext="{Binding FindTextViewModel}"/>
                    </Border>
                    
                </controls:EntranceAnimationContentControl>
    

    Here's the class by the way:

        class EntranceAnimationContentControl : Windows.UI.Xaml.Controls.ContentControl
        {
            #region dependency property
    
            public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register(
              "IsOpen",
              typeof(bool),
              typeof(EntranceAnimationContentControl),
              new PropertyMetadata(false, new PropertyChangedCallback(OnIsOpenChanged))
            );
    
            public bool IsOpen
            {
                get
                {
                    return (bool)GetValue(IsOpenProperty);
                }
                set
                {
                    SetValue(IsOpenProperty, value);
                }
            }
    
            private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                EntranceAnimationContentControl ctrl = d as EntranceAnimationContentControl; //null checks omitted
                bool s = (bool)e.NewValue; //null checks omitted
                if (s) // opening
                {
                    ctrl.Open();
                }
                else // closing
                {
                    ctrl.Close();
                }
            }
    
    
    
            public static readonly DependencyProperty EntranceAnimationProperty = DependencyProperty.Register(
              "EntranceAnimation",
              typeof(Storyboard),
              typeof(EntranceAnimationContentControl),
              new PropertyMetadata(false, new PropertyChangedCallback(OnEntranceAnimationChanged))
            );
    
            public Storyboard EntranceAnimation
            {
                get
                {
                    return (Storyboard)GetValue(EntranceAnimationProperty);
                }
                set
                {
                    SetValue(EntranceAnimationProperty, value);
                }
            }
    
            private static void OnEntranceAnimationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                EntranceAnimationContentControl ctrl = d as EntranceAnimationContentControl; //null checks omitted
                Storyboard storyBoard = e.NewValue as Storyboard;
                if (storyBoard != null)
                {
                    ctrl.EntranceHandler = new EventHandler<Object>(ctrl.EntranceAnimation_Completed);
                    storyBoard.Completed += ctrl.EntranceHandler;
                }
            }
    
            private EventHandler<object> EntranceHandler;
    
    
            public static readonly DependencyProperty ExitAnimationProperty = DependencyProperty.Register(
              "ExitAnimation",
              typeof(Storyboard),
              typeof(EntranceAnimationContentControl),
              new PropertyMetadata(false)
            );
    
            public Storyboard ExitAnimation
            {
                get
                {
                    return (Storyboard)GetValue(ExitAnimationProperty);
                }
                set
                {
                    SetValue(ExitAnimationProperty, value);
                }
            }
    
            #endregion dependency property
    
    
            private EventHandler<object> _ExitCompletedHandler;
    
            protected void Open()
            {
                System.Diagnostics.Debug.WriteLine("opening");
                this.Visibility = Windows.UI.Xaml.Visibility.Visible;
                if (EntranceAnimation != null)
                {
                    EntranceAnimation.Begin();
                }
            }
    
            protected void Close()
            {
                System.Diagnostics.Debug.WriteLine("closing");
                if (ExitAnimation != null)
                {
                    if (_ExitCompletedHandler == null)
                    {
                        _ExitCompletedHandler = new EventHandler<object>(ExitAnimation_Completed);
                        ExitAnimation.Completed += _ExitCompletedHandler;
                    }
                    ExitAnimation.Begin();
                }
                else
                {
                    this.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
                }
            }
    
            private void EntranceAnimation_Completed(object sender, object e)
            {
                int a = 0;
            }
    
            void ExitAnimation_Completed(object sender, object e)
            {
                this.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
            }
        }

    Could you tell me why this might be a worse approach?

    Cheers,

    Tomas


    Tuesday, July 15, 2014 9:42 PM
  • Hi T Hofmann,

    I don't think it is a worse approach. The Template in Windows Store App is used to define the Animation/State/UIElement inside the control, don't feel odd since it's normal.

    Let's say for instance a button, to style the button we need template to describe what inside the button, like several rectangles, some TextBlocks. To ensure the button has different performances under different situations, we need some Visual States or animations, and etc.

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Wednesday, July 16, 2014 3:36 AM
    Moderator
  • Hi James,

    Thanks for the answer.

    What I meant was that the animation isn't for the button at all. Instead, some completely different element is moved about.

    For example, you might have a MainView with a Rectangle and a Button. The Rectangle on the top of the screen and the button on the bottom of the screen. When you click the button, the rectangle wiggles.

    It seems unnatural to me to stick that animation inside the button's style.

    Also, the reason I asked what was a better approach was because I was wondering if there was something I was missing (some functionality) with my approach as opposed to making it part of the button's visual states.

    Best Regards,

    Tomas Hofamnn

    Monday, July 21, 2014 11:24 PM
  • I have another very generic way to deal with it using my StoryboardPlayer utility class

    using System;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Media.Animation;
    
    namespace Kaushik.Utilities
    {
        public class StoryboardPlayer : FrameworkElement
        {
            #region Dependency Properties
            public static readonly DependencyProperty TriggerProperty =
                DependencyProperty.Register("Trigger", typeof(object), typeof(StoryboardPlayer), new PropertyMetadata(null, onTriggerChanged));
    
            public static readonly DependencyProperty MyPropertyProperty =
                DependencyProperty.Register("Storyboard", typeof(Storyboard), typeof(StoryboardPlayer), new PropertyMetadata(null));
            #endregion Dependency Properties
    
            #region Properties
            public object Trigger
            {
                get { return (object)GetValue(TriggerProperty); }
                set { SetValue(TriggerProperty, value); }
            }
    
            public Storyboard Storyboard
            {
                get { return (Storyboard)GetValue(MyPropertyProperty); }
                set { SetValue(MyPropertyProperty, value); }
            }
            #endregion Properties
    
            #region Constructor
            public StoryboardPlayer()
            {
                this.Visibility = Visibility.Collapsed;
            }
            #endregion Constructor
    
            #region Trigger value change handler
            private static void onTriggerChanged(DependencyObject source, DependencyPropertyChangedEventArgs changeArguments)
            {
                StoryboardPlayer storyboardPlayer = source as StoryboardPlayer;
    
                if (storyboardPlayer != null
                    && storyboardPlayer.Trigger != null
                    && storyboardPlayer.Storyboard != null)
                {
                    Type triggerType = storyboardPlayer.Trigger.GetType();
    
                    switch (triggerType.ToString())
                    {
                        case "System.Boolean":
                            if ((Boolean)storyboardPlayer.Trigger)
                            {
                                storyboardPlayer.Storyboard.Begin();
                            }
                            else
                            {
                                storyboardPlayer.Storyboard.Stop();
                            }
                            break;
                        //Implement other types that need to be supported or use a Value Converter in binding to make it Boolean
                    }
                }
            }
            #endregion Trigger value change handler
        }
    }

    This how you can use it in XAML

    <Page
        x:Class="MsdnSample22072014.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:MsdnSample22072014"
        xmlns:k="using:Kaushik.Utilities"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
        <Page.Resources>
            <Storyboard x:Name="SampleStoryboard">
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="Button1">
                    <EasingDoubleKeyFrame KeyTime="0" Value="814.925"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="405.97"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="361.194"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="Button1">
                    <EasingDoubleKeyFrame KeyTime="0" Value="395.522"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="308.955"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="628.358"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="Button2">
                    <EasingDoubleKeyFrame KeyTime="0" Value="300"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="694.03"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="626.866"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:7" Value="594.03"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="Button2">
                    <EasingDoubleKeyFrame KeyTime="0" Value="486.567"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="179.104"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="544.776"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:7" Value="141.791"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="Button5">
                    <EasingDoubleKeyFrame KeyTime="0" Value="443.284"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="119.403"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="753.731"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:7" Value="570.149"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="Button5">
                    <EasingDoubleKeyFrame KeyTime="0" Value="5.97"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="223.88"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="289.552"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:7" Value="279.104"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="Button4">
                    <EasingDoubleKeyFrame KeyTime="0" Value="505.97"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="540.298"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="119.402"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="Button4">
                    <EasingDoubleKeyFrame KeyTime="0" Value="-28.358"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="394.03"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="441.791"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="Button3">
                    <EasingDoubleKeyFrame KeyTime="0" Value="419.403"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="11.94"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="888.059"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:7" Value="752.238"/>
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="Button3">
                    <EasingDoubleKeyFrame KeyTime="0" Value="268.657"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="-53.731"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="261.194"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:7" Value="392.537"/>
                </DoubleAnimationUsingKeyFrames>
            </Storyboard>
        </Page.Resources>
        <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <Button x:Name="Button1" Content="Sample 1" RenderTransformOrigin="0.5,0.5">
                <Button.RenderTransform>
                    <CompositeTransform/>
                </Button.RenderTransform>
            </Button>
            <Button x:Name="Button2" Content="Sample 2" RenderTransformOrigin="0.5,0.5">
                <Button.RenderTransform>
                    <CompositeTransform/>
                </Button.RenderTransform>
            </Button>
            <Button x:Name="Button3" Content="Sample 3" RenderTransformOrigin="0.5,0.5">
                <Button.RenderTransform>
                    <CompositeTransform/>
                </Button.RenderTransform>
            </Button>
            <Button x:Name="Button4" Content="Sample 4" RenderTransformOrigin="0.5,0.5">
                <Button.RenderTransform>
                    <CompositeTransform/>
                </Button.RenderTransform>
            </Button>
            <Button x:Name="Button5" Content="Sample 5" RenderTransformOrigin="0.5,0.5">
                <Button.RenderTransform>
                    <CompositeTransform/>
                </Button.RenderTransform>
            </Button>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Use me to start and stop animation!" Margin="5" FontSize="24"/>
                <CheckBox x:Name="control" Margin="5"/>
            </StackPanel>
            <k:StoryboardPlayer Trigger="{Binding ElementName=control, Path=IsChecked}" Storyboard="{StaticResource SampleStoryboard}"/>
        </StackPanel>
    </Page>

    You can implement my player class where you support multiple story boards and have conditional logic to play one of them.

    I am just posting this as an alternate.


    -- Vishal Kaushik --

    Please 'Mark as Answer' if my post answers your question and 'Vote as Helpful' if it helps you. Happy Coding!!!



    • Edited by Vishal Kaushik Tuesday, July 22, 2014 6:15 PM
    • Marked as answer by T Hofmann Wednesday, July 23, 2014 3:52 PM
    Tuesday, July 22, 2014 6:02 PM
  • Hi Vishal Kaushik,

    That is a very nice construct. It's quite simple and takes up a little less room that my solution. Yours is more flexible too, as you can add any animation for anything.

    The thing I like about my solution is that it handled visibility for you, and it's quite easy to bind to a Boolean for when to show and when not to.

    Thanks for the suggestion. It seems like there's not a standard solution, but several out there that have different strengths and weaknesses. I will marks yours as an answer, since it's a solution and I feel like I got my question answered.

    Thanks,

    Tomas

    Wednesday, July 23, 2014 3:56 PM