Click here to Skip to main content
15,895,011 members

Transition effects in wpf application

koleraba asked:

Open original thread
Hi
I am using the following control for animated transitions between views:

C#
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
Tags: C# (C# 4.0), WPF, Animation

Plain Text
ASM
ASP
ASP.NET
BASIC
BAT
C#
C++
COBOL
CoffeeScript
CSS
Dart
dbase
F#
FORTRAN
HTML
Java
Javascript
Kotlin
Lua
MIDL
MSIL
ObjectiveC
Pascal
PERL
PHP
PowerShell
Python
Razor
Ruby
Scala
Shell
SLN
SQL
Swift
T4
Terminal
TypeScript
VB
VBScript
XML
YAML

Preview



When answering a question please:
  1. Read the question carefully.
  2. Understand that English isn't everyone's first language so be lenient of bad spelling and grammar.
  3. If a question is poorly phrased then either ask for clarification, ignore it, or edit the question and fix the problem. Insults are not welcome.
  4. Don't tell someone to read the manual. Chances are they have and don't get it. Provide an answer or move on to the next question.
Let's work to help developers, not make them feel stupid.
Please note that all posts will be submitted under the http://www.codeproject.com/info/cpol10.aspx.



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900