Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: WPF C#4.0 Animation
Hi
 
I am using the following control for animated transitions between views:
 
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using EasyTouch.Gui.Selector;
using Microsoft.Expression.Media.Effects;
 
namespace EasyTouch.Gui.Control
{
    /// <summary>
    /// Control used to animate the transition between shown elements
    /// </summary>
    public class TransitionControl : ContentControl
    {
        // Private Fields
        private ContentPresenter _contentPresenter;
 
        /// <summary>
        /// Static constructor
        /// </summary>
        static TransitionControl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TransitionControl), new FrameworkPropertyMetadata(typeof(TransitionControl)));
            ContentProperty.OverrideMetadata(typeof(TransitionControl), new FrameworkPropertyMetadata(OnContentPropertyChanged));
        }
 
        /// <summary>
        /// ContentTransitionSelector depencency property
        /// </summary>
        public static readonly DependencyProperty ContentTransitionSelectorProperty = DependencyProperty.Register("ContentTransitionSelector", typeof (TransitionSelector), typeof (TransitionControl),
                                                                                                                  new UIPropertyMetadata(null));
        /// <summary>
        /// Gets or sets the TransitionSelector used to retrive the transition effect
        /// </summary>
        public TransitionSelector ContentTransitionSelector
        {
            get { return (TransitionSelector)GetValue(ContentTransitionSelectorProperty); }
            set { SetValue(ContentTransitionSelectorProperty, value); }
        }
 
        /// <summary>
        /// Transition duration dependency property
        /// </summary>
        public static readonly DependencyProperty DurationProperty = DependencyProperty.Register("Duration", typeof (TimeSpan), typeof (TransitionControl),
                                                                                                 new UIPropertyMetadata(TimeSpan.FromSeconds(1)));
        /// <summary>
        /// Gets or sets the transition duration
        /// </summary>
        public TimeSpan Duration
        {
            get { return (TimeSpan)GetValue(DurationProperty); }
            set { SetValue(DurationProperty, value); }
        }
 
        /// <summary>
        /// The EasingFunction depencendy property
        /// </summary>
        public static readonly DependencyProperty EasingFunctionProperty = DependencyProperty.Register("EasingFunction", typeof (IEasingFunction), typeof (TransitionControl),
                                                                                                        new UIPropertyMetadata(null));
        /// <summary>
        /// Gets or sets <see cref="IEasingFunction"/> instance used by the transition animation
        /// </summary>
        public IEasingFunction EasingFunction
        {
            get { return (IEasingFunction)GetValue(EasingFunctionProperty); }
            set { SetValue(EasingFunctionProperty, value); }
        }
 
        /// <summary>
        /// Enable transition dependency property
        /// </summary>
        public static readonly DependencyProperty EnableTransitionsProperty = DependencyProperty.Register("EnableTransitions", typeof(bool), typeof(TransitionControl),
                                                                                                            new UIPropertyMetadata(true));
        /// <summary>
        /// Gets or sets the value indicating whether the effect will be used during the content transition
        /// </summary>
        public bool EnableTransitions
        {
            get { return (bool)GetValue(EnableTransitionsProperty); }
            set { SetValue(EnableTransitionsProperty, value); }
        }
 
        /// <summary>
        /// Executes when the ContentProperty is changed
        /// </summary>
        /// <param name="dp">The control whose content has changed</param>
        /// <param name="args">Additional information about old and new content</param>
        private static void OnContentPropertyChanged(DependencyObject dp, DependencyPropertyChangedEventArgs args)
        {
            ((TransitionControl) dp).OnContentChanged(args.OldValue, args.NewValue);
        }
 
        /// <summary>
        /// Executes when the Content of the control is changed
        /// </summary>
        /// <param name="oldContent">The old content</param>
        /// <param name="newContent">The new content</param>
        protected override void OnContentChanged(object oldContent, object newContent)
        {
            if (oldContent != null && newContent != null)
            {
                AnimateContent(oldContent, newContent);
            }
            else
            {
                AnimateContent(newContent);
            }
        }
 
        /// <summary>
        /// Shows the new content using the animation
        /// </summary>
        /// <param name="content">The controls new content</param>
        private void AnimateContent(object content)
        {
            if(IsLoaded)
            {
                _contentPresenter.Content = content;
            }
            else
            {
                RoutedEventHandler handler = null;
                handler = delegate
                              {
                                  Loaded -= handler;
                                  _contentPresenter.Content = content;
                              };
                Loaded += handler;
            }
        }
 
        /// <summary>
        /// Shows the new content using the animation
        /// </summary>
        /// <param name="oldContent">The controls old content</param>
        /// <param name="newContent">The controls new content</param>
        private void AnimateContent(object oldContent, object newContent)
        {
            var oldContentVisual = GetVisualChild();
            var tier = (RenderCapability.Tier >> 16);
 
            // If the selector is not specified or the animation is not enabled or not supported show the new content without animation
            if (EnableTransitions == false || ContentTransitionSelector == null || oldContentVisual == null || tier < 2)
            {
                SetNonVisualChild(newContent);
                return;
            }
 
            // create the transition
            var transitionEffect = ContentTransitionSelector.GetTransition(oldContent, newContent, this);
            if (transitionEffect == null)
            {
                throw new InvalidOperationException("Returned transition effect is null.");
            }
 
            // create the animation
            var da = new DoubleAnimation(0.0, 1.0, new Duration(Duration), FillBehavior.HoldEnd);
            da.Completed += delegate
            {
                ApplyEffect(null);
            };
            if (EasingFunction != null)
            {
                da.EasingFunction = EasingFunction;
            }
            else
            {
                da.AccelerationRatio = 0.5;
                da.DecelerationRatio = 0.5;
            }
            transitionEffect.BeginAnimation(TransitionEffect.ProgressProperty, da);
 
            var oldVisualBrush = new VisualBrush(oldContentVisual);
            transitionEffect.OldImage = oldVisualBrush;
            SetNonVisualChild(newContent);
            ApplyEffect(transitionEffect);
        }
 
        /// <summary>
        /// Retrives the first visual child of the current control
        /// </summary>
        /// <returns></returns>
        private FrameworkElement GetVisualChild()
        {
            return VisualTreeHelper.GetChildrenCount(_contentPresenter) == 0 ? null : VisualTreeHelper.GetChild(_contentPresenter, 0) as FrameworkElement;
        }
 
        /// <summary>
        /// Sets the non visual child (data) of the control
        /// </summary>
        /// <param name="content">The non-visual content</param>
        private void SetNonVisualChild(object content)
        {
            _contentPresenter.Content = content;
        }
 
        /// <summary>
        /// Applies the specified transition effect
        /// </summary>
        /// <param name="effect">The transition effect to apply</param>
        private void ApplyEffect(TransitionEffect effect)
        {
            _contentPresenter.Effect = effect;
        }
 
        /// <summary>
        /// Executes when the template is applied to the current control
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _contentPresenter = (ContentPresenter)Template.FindName("PART_ContentHost", this);
        }
    }
}
 
 
The control is based on article found on the internet. I often use the ContentControl so that insted of implementing the ContentTemplateSelector, I just create a class derived from the ContentControl and than override the OnContentChanged method where I select the appropriate ContentTemplate and than call the base.OnContentChanged method. So I tried the same approach here and it does'n work - the views change but the transition is not animated. I tried to mark the OnContentChanged method in TransitionControl with "new" keyword so the derived class would override the correct method but it did not help. After debugging I found out that the GetVisualChild() method always returns null and so the transition is not animated. If I don't override the TransitionControl and just use it in xaml and implement an appropriate ContentTemplateSelector the control work Ok, but I am still wondering what the problem is with the approach described above. Any ideas will be appreciated.
 
Uros
Posted 25-Dec-12 6:19am
koleraba1.2K

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 DamithSL 400
1 Maciej Los 222
2 OriginalGriff 213
3 BillWoodruff 130
4 Zoltán Zörgő 85
0 OriginalGriff 7,969
1 DamithSL 6,139
2 Sergey Alexandrovich Kryukov 5,449
3 Maciej Los 5,309
4 Kornfeld Eliyahu Peter 4,539


Advertise | Privacy | Mobile
Web04 | 2.8.141223.1 | Last Updated 25 Dec 2012
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100