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
{
public class TransitionControl : ContentControl
{
private ContentPresenter _contentPresenter;
static TransitionControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TransitionControl), new FrameworkPropertyMetadata(typeof(TransitionControl)));
ContentProperty.OverrideMetadata(typeof(TransitionControl), new FrameworkPropertyMetadata(OnContentPropertyChanged));
}
public static readonly DependencyProperty ContentTransitionSelectorProperty = DependencyProperty.Register("ContentTransitionSelector", typeof (TransitionSelector), typeof (TransitionControl),
new UIPropertyMetadata(null));
public TransitionSelector ContentTransitionSelector
{
get { return (TransitionSelector)GetValue(ContentTransitionSelectorProperty); }
set { SetValue(ContentTransitionSelectorProperty, value); }
}
public static readonly DependencyProperty DurationProperty = DependencyProperty.Register("Duration", typeof (TimeSpan), typeof (TransitionControl),
new UIPropertyMetadata(TimeSpan.FromSeconds(1)));
public TimeSpan Duration
{
get { return (TimeSpan)GetValue(DurationProperty); }
set { SetValue(DurationProperty, value); }
}
public static readonly DependencyProperty EasingFunctionProperty = DependencyProperty.Register("EasingFunction", typeof (IEasingFunction), typeof (TransitionControl),
new UIPropertyMetadata(null));
public IEasingFunction EasingFunction
{
get { return (IEasingFunction)GetValue(EasingFunctionProperty); }
set { SetValue(EasingFunctionProperty, value); }
}
public static readonly DependencyProperty EnableTransitionsProperty = DependencyProperty.Register("EnableTransitions", typeof(bool), typeof(TransitionControl),
new UIPropertyMetadata(true));
public bool EnableTransitions
{
get { return (bool)GetValue(EnableTransitionsProperty); }
set { SetValue(EnableTransitionsProperty, value); }
}
private static void OnContentPropertyChanged(DependencyObject dp, DependencyPropertyChangedEventArgs args)
{
((TransitionControl) dp).OnContentChanged(args.OldValue, args.NewValue);
}
protected override void OnContentChanged(object oldContent, object newContent)
{
if (oldContent != null && newContent != null)
{
AnimateContent(oldContent, newContent);
}
else
{
AnimateContent(newContent);
}
}
private void AnimateContent(object content)
{
if(IsLoaded)
{
_contentPresenter.Content = content;
}
else
{
RoutedEventHandler handler = null;
handler = delegate
{
Loaded -= handler;
_contentPresenter.Content = content;
};
Loaded += handler;
}
}
private void AnimateContent(object oldContent, object newContent)
{
var oldContentVisual = GetVisualChild();
var tier = (RenderCapability.Tier >> 16);
if (EnableTransitions == false || ContentTransitionSelector == null || oldContentVisual == null || tier < 2)
{
SetNonVisualChild(newContent);
return;
}
var transitionEffect = ContentTransitionSelector.GetTransition(oldContent, newContent, this);
if (transitionEffect == null)
{
throw new InvalidOperationException("Returned transition effect is null.");
}
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);
}
private FrameworkElement GetVisualChild()
{
return VisualTreeHelper.GetChildrenCount(_contentPresenter) == 0 ? null : VisualTreeHelper.GetChild(_contentPresenter, 0) as FrameworkElement;
}
private void SetNonVisualChild(object content)
{
_contentPresenter.Content = content;
}
private void ApplyEffect(TransitionEffect effect)
{
_contentPresenter.Effect = effect;
}
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