/ custom-control

A control that plays key frame animation

USAGE

Add this to your XAML:

 <cc:KeyFrameAnimationControl 
                        PlayAnimation="{x:Bind PhotoVM.PlayLikeAnimation,Mode=TwoWay}"  
                        ImagesSource="{x:Bind PhotoVM.LikeIconsSrc,Mode=OneWay}" 
                        AnimationTimeSpan="300" 
                        IsStayInLastFrame="False"/>

Key property:

  • PlayAnimation is a bool type property. To begin the animation, just set this property to true.

  • ImagesSource is a IEnumerable<Image> type property. It's the source of images in each frame in the animation.

  • AnimationTimeSpan is an int type property. It defines the timespan of the animation.

  • AutoRePlay is a bool type property,which by default is false. Setting it to true means the animation will repeat after it reach the end.

Source code

XAML:

<Style TargetType="local:KeyFrameAnimationControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:KeyFrameAnimationControl">
                     <Grid x:Name="RootGrid"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

cs:

public class KeyFrameAnimationControl : ContentControl
    {
        public IEnumerable<Image> ImagesSource
        {
            get { return (IEnumerable<Image>)GetValue(ImagesSourceProperty); }
            set { SetValue(ImagesSourceProperty, value); }
        }

        public static readonly DependencyProperty ImagesSourceProperty =
            DependencyProperty.Register("ImagesSource", typeof(IEnumerable<Image>), typeof(KeyFrameAnimationControl), new PropertyMetadata(null));

        public int AnimationTimeSpan
        {
            get { return (int)GetValue(AnimationTimeSpanProperty); }
            set { SetValue(AnimationTimeSpanProperty, value); }
        }

        public static readonly DependencyProperty AnimationTimeSpanProperty =
            DependencyProperty.Register("AnimationTimeSpan", typeof(int), typeof(KeyFrameAnimationControl), new PropertyMetadata(1000));

        public bool PlayAnimation
        {
            get { return (bool)GetValue(PlayAnimationProperty); }
            set { SetValue(PlayAnimationProperty, value); }
        }

        public static readonly DependencyProperty PlayAnimationProperty =
            DependencyProperty.Register("PlayAnimation", typeof(bool), typeof(KeyFrameAnimationControl), new PropertyMetadata(false,
                (sender,e)=>
                {
                    var control = sender as KeyFrameAnimationControl;
                    if ((bool)e.NewValue) control.StartAnimation();
                }));

        public bool AutoRePlay
        {
            get { return (bool)GetValue(AutoRePlayProperty); }
            set { SetValue(AutoRePlayProperty, value); }
        }

        public static readonly DependencyProperty AutoRePlayProperty =
            DependencyProperty.Register("AutoRePlay", typeof(bool), typeof(KeyFrameAnimationControl), new PropertyMetadata(false));

        public bool IsStayInLastFrame
        {
            get { return (bool)GetValue(IsStayInLastFrameProperty); }
            set { SetValue(IsStayInLastFrameProperty, value); }
        }

        public static readonly DependencyProperty IsStayInLastFrameProperty =
            DependencyProperty.Register("IsStayInLastFrame", typeof(bool), typeof(KeyFrameAnimationControl), new PropertyMetadata(true));

        private Grid RootGrid;
        private TaskCompletionSource<int> tcs;
        private DispatcherTimer timer = new DispatcherTimer();
        private int currentFrame = 0;

        public KeyFrameAnimationControl()
        {
            DefaultStyleKey = typeof(KeyFrameAnimationControl);
            tcs = new TaskCompletionSource<int>();
        }

        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            RootGrid = GetTemplateChild("RootGrid") as Grid;
            InitialStoryBoard();
            tcs.SetResult(0);
        }

        private void InitialStoryBoard()
        {
            if(ImagesSource==null)
            {
                throw new ArgumentException("The ImagesSource should not be null!");
            }
            else if(ImagesSource.Count()==0)
            {
                throw new ArgumentException("The ImagesSources count should greater than 1!");
            }
            foreach (var image in ImagesSource)
            {
                RootGrid.Children.Add(image);
            }

            timer.Interval = new TimeSpan(0, 0, 0, 0, (AnimationTimeSpan / ImagesSource.Count()));
            timer.Tick += ((sender, et) =>
            {
                currentFrame++;

                //reach the last frame
                if (currentFrame == ImagesSource.Count())
                {
                    currentFrame = 0;
                    if (!AutoRePlay)
                    {
                        PlayAnimation = false;
                        timer.Stop();
                    }
                    if(!IsStayInLastFrame)
                    {
                        DismissAll();
                    }
                    return;
                }
                var previousFrame = currentFrame == 0 ? ImagesSource.Count()-1 : currentFrame - 1;
                ImagesSource.ElementAt(previousFrame).Visibility = Visibility.Collapsed;
                ImagesSource.ElementAt(currentFrame).Visibility = Visibility.Visible;
            });
        }

        public void StartAnimation()
        {
            currentFrame = 0;
            timer.Start();
        }

        public void StopAnimation()
        {
            timer.Stop();
            currentFrame = 0;
        }

        public void DismissAll()
        {
            ImagesSource.ToList().ForEach(s => s.Visibility = Visibility.Collapsed);
        }
    }