using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Tango.SharedUI.Controls
{
///
/// Represents a control for holding a list of content controls and creates transition effects between them.
///
public partial class MultiTransitionControl : UserControl
{
private int index;
private bool freezeAnimation;
private ContentControl element1 = null;
private ContentControl element2 = null;
private ContentControl fromElement;
private ContentControl toElement;
private Action navigationCompleteAction;
private bool _loaded;
#region Events
///
/// Occurs when the transition has completed.
///
public event Action TransitionComplete;
#endregion
#region Constructors
///
/// Initialize a new instance of MultiTransitionControl.
///
public MultiTransitionControl()
{
Controls = new List();
index = 0;
InitializeComponent();
this.Loaded += MultiTransitionControl_Loaded;
}
#endregion
#region Event Handlers
private void MultiTransitionControl_Loaded(object sender, RoutedEventArgs e)
{
if (!_loaded)
{
RefreshControls();
_loaded = true;
}
}
public void RefreshControls()
{
mainGrid.Children.Clear();
foreach (ContentControl control in Controls)
{
control.Visibility = System.Windows.Visibility.Hidden;
mainGrid.Children.Add(control);
}
if (Controls.Count > 0)
{
Controls[0].Visibility = System.Windows.Visibility.Visible;
SelectedControl = Controls[0];
fromElement = SelectedControl;
}
}
private void ani_BackCompleted(object sender, EventArgs e)
{
fromElement = toElement;
toElement = null;
freezeAnimation = true;
this.ApplyAnimationClock(MultiTransitionControl.MixProperty, null);
Mix = 0;
index++;
freezeAnimation = false;
IsAnimating = false;
OnTransitionCompleted();
}
private void ani_NextCompleted(object sender, EventArgs e)
{
fromElement = toElement;
toElement = null;
freezeAnimation = true;
this.ApplyAnimationClock(MultiTransitionControl.MixProperty, null);
Mix = 0;
index++;
freezeAnimation = false;
IsAnimating = false;
OnTransitionCompleted();
}
#endregion
#region Properties
///
/// Gets or sets the available content controls nested in the MultiTransitionControl.
///
public List Controls { get; set; }
///
/// Gets or sets the transition style.
///
public TransitionTypeEnum TransitionType
{
get { return (TransitionTypeEnum)GetValue(TransitionTypeProperty); }
set { SetValue(TransitionTypeProperty, value); }
}
public static readonly DependencyProperty TransitionTypeProperty =
DependencyProperty.Register("TransitionType", typeof(TransitionTypeEnum), typeof(MultiTransitionControl), new PropertyMetadata(TransitionTypeEnum.Fade) { PropertyChangedCallback = new PropertyChangedCallback(TransitionTypeChanged) });
private static void TransitionTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as MultiTransitionControl).ResetTransformation();
}
///
/// This is where the actual transition occurs.
///
private double Mix
{
get { return (double)GetValue(MixProperty); }
set
{
SetValue(MixProperty, value);
if (!freezeAnimation)
{
UpdateMix(value);
}
}
}
private static readonly DependencyProperty MixProperty =
DependencyProperty.Register("Mix", typeof(double), typeof(MultiTransitionControl), new PropertyMetadata(new PropertyChangedCallback(MixChanged)));
private static void MixChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MultiTransitionControl tr = d as MultiTransitionControl;
double value = (double)e.NewValue;
tr.UpdateMix(value);
}
///
/// Gets or sets whether to always include a cross fade transition along with the selected transition style.
///
public bool AlwaysFade
{
get { return (bool)GetValue(AlwaysFadeProperty); }
set { SetValue(AlwaysFadeProperty, value); }
}
public static readonly DependencyProperty AlwaysFadeProperty =
DependencyProperty.Register("AlwaysFade", typeof(bool), typeof(MultiTransitionControl), new PropertyMetadata(false));
///
/// Gets or sets the interval in milliseconds for the transition to complete.
///
public int AnimationTime
{
get { return (int)GetValue(AnimationTimeProperty); }
set { SetValue(AnimationTimeProperty, value); }
}
public static readonly DependencyProperty AnimationTimeProperty =
DependencyProperty.Register("AnimationTime", typeof(int), typeof(MultiTransitionControl), new PropertyMetadata(1000));
///
/// Gets or sets the transition 'ease in' time.
///
public double AnimationAcceleration
{
get { return (double)GetValue(AnimationAccelerationProperty); }
set { SetValue(AnimationAccelerationProperty, value); }
}
public static readonly DependencyProperty AnimationAccelerationProperty =
DependencyProperty.Register("AnimationAcceleration", typeof(double), typeof(MultiTransitionControl), new PropertyMetadata(0.5));
///
/// Gets or sets the transition 'ease out' time.
///
public double AnimationDeceleration
{
get { return (double)GetValue(AnimationDecelerationProperty); }
set { SetValue(AnimationDecelerationProperty, value); }
}
public static readonly DependencyProperty AnimationDecelerationProperty =
DependencyProperty.Register("AnimationDeceleration", typeof(double), typeof(MultiTransitionControl), new PropertyMetadata(0.5));
///
/// Gets or sets whether a transition is taking place at the moment.
///
public bool IsAnimating
{
get { return (bool)GetValue(IsAnimatingProperty); }
private set { SetValue(IsAnimatingProperty, value); }
}
public static readonly DependencyProperty IsAnimatingProperty =
DependencyProperty.Register("IsAnimating", typeof(bool), typeof(MultiTransitionControl), new PropertyMetadata(false));
///
/// Gets or sets currently visible content control.
///
public ContentControl SelectedControl
{
get { return (ContentControl)GetValue(SelectedControlProperty); }
set { SetValue(SelectedControlProperty, value); }
}
public static readonly DependencyProperty SelectedControlProperty =
DependencyProperty.Register("SelectedControl", typeof(ContentControl), typeof(MultiTransitionControl), new PropertyMetadata(null));
#endregion
#region Methods
///
/// Updates the mix.
///
/// The value.
private void UpdateMix(double value)
{
if (freezeAnimation) return;
if (element1 == null || element2 == null)
{
return;
}
element1.Visibility = System.Windows.Visibility.Visible;
element2.Visibility = System.Windows.Visibility.Visible;
if (TransitionType == TransitionTypeEnum.Fade)
{
element1.RenderTransform = null;
element2.RenderTransform = null;
element1.Opacity = value;
element2.Opacity = 1 - value;
return;
}
else if (TransitionType == TransitionTypeEnum.Slide)
{
double v = value * 100;
v = (v * this.ActualWidth) / 100;
element2.RenderTransform = new TranslateTransform(v, 0);
element1.RenderTransform = new TranslateTransform(v - this.ActualWidth, 0);
}
else if (TransitionType == TransitionTypeEnum.Zoom)
{
element1.RenderTransformOrigin = new Point(0.5, 0.5);
element2.RenderTransformOrigin = new Point(0.5, 0.5);
element1.RenderTransform = new ScaleTransform(value, value);
element2.RenderTransform = new ScaleTransform(1 - value, 1 - value);
}
else if (TransitionType == TransitionTypeEnum.Spin)
{
double v = value * 100;
v = (v * 360) / 100;
var group1 = new TransformGroup();
group1.Children.Add(new RotateTransform(v));
group1.Children.Add(new ScaleTransform(value, value));
var group2 = new TransformGroup();
group2.Children.Add(new RotateTransform(360 - v));
group2.Children.Add(new ScaleTransform(1 - value, 1 - value));
element1.RenderTransform = group1;
element2.RenderTransform = group2;
}
else if (TransitionType == TransitionTypeEnum.Carousel)
{
double v = value * 100;
v = (v * this.ActualWidth) / 100;
var group1 = new TransformGroup();
group1.Children.Add(new ScaleTransform(value, value));
group1.Children.Add(new TranslateTransform(v - this.ActualWidth, 0));
var group2 = new TransformGroup();
group2.Children.Add(new TranslateTransform(v * 2, 0));
group2.Children.Add(new ScaleTransform(1 - value, 1 - value));
element1.RenderTransform = group1;
element2.RenderTransform = group2;
}
else if (TransitionType == TransitionTypeEnum.Skew)
{
double v = value * 100;
v = (v * 180) / 100;
element2.RenderTransform = new SkewTransform(v, 0);
element1.RenderTransform = new SkewTransform(v - 180, 0);
}
else if (TransitionType == TransitionTypeEnum.Push)
{
element1.RenderTransformOrigin = new Point(1, 0.5);
element2.RenderTransformOrigin = new Point(0, 0.5);
element1.RenderTransform = new ScaleTransform(value, 1);
element2.RenderTransform = new ScaleTransform(1 - value, 1);
}
if (AlwaysFade)
{
element1.Opacity = value;
element2.Opacity = 1 - value;
}
}
///
/// Resets the transformation.
///
private void ResetTransformation()
{
foreach (ContentControl control in Controls)
{
control.RenderTransformOrigin = new Point(0.5, 0.5);
}
}
///
/// Execute a transition between the current selected control and the specified content control tag.
///
/// Tag of content control to navigate to.
/// DataContext to assign to the specified content control.
/// Navigation completed callback delegate.
public void AutoNavigate(object tag, object dataContext = null, Action navigationComplete = null)
{
if (IsAnimating)
{
return;
}
ContentControl control = Controls.SingleOrDefault(x => x.Tag != null && x.Tag.ToString() == tag.ToString());
if (control == SelectedControl)
{
return;
}
if (control == null)
{
throw new Exception("Control with tag '" + tag.ToString() + "' not found! (Transition Control)");
}
if (dataContext != null)
{
control.DataContext = dataContext;
}
if (Controls.IndexOf(control) > Controls.IndexOf(fromElement))
{
navigationCompleteAction = navigationComplete;
toElement = control;
SelectedControl = control;
Next();
}
else if (Controls.IndexOf(control) < Controls.IndexOf(fromElement))
{
navigationCompleteAction = navigationComplete;
toElement = control;
SelectedControl = control;
Back();
}
}
private void Next()
{
if (IsAnimating)
{
return;
}
IsAnimating = true;
if (Controls.IndexOf(toElement) > Controls.IndexOf(fromElement))
{
element1 = toElement;
element2 = fromElement;
}
else
{
element1 = fromElement;
element2 = toElement;
}
if (element2 == null)
{
SelectedControl = Controls[0];
fromElement = SelectedControl;
element2 = fromElement;
}
freezeAnimation = true;
this.ApplyAnimationClock(MultiTransitionControl.MixProperty, null);
Mix = 0;
freezeAnimation = false;
DoubleAnimation ani = new DoubleAnimation(1, new Duration(TimeSpan.FromMilliseconds(AnimationTime)), FillBehavior.HoldEnd);
ani.AccelerationRatio = AnimationAcceleration;
ani.DecelerationRatio = AnimationDeceleration;
ani.Completed += ani_NextCompleted;
this.BeginAnimation(MultiTransitionControl.MixProperty, ani);
}
private void Back()
{
if (IsAnimating) return;
IsAnimating = true;
if (Controls.IndexOf(toElement) > Controls.IndexOf(fromElement))
{
element1 = toElement;
element2 = fromElement;
}
else
{
element1 = fromElement;
element2 = toElement;
}
freezeAnimation = true;
this.ApplyAnimationClock(MultiTransitionControl.MixProperty, null);
Mix = 1;
freezeAnimation = false;
DoubleAnimation ani = new DoubleAnimation(0, new Duration(TimeSpan.FromMilliseconds(AnimationTime)), FillBehavior.HoldEnd);
ani.Completed += ani_BackCompleted;
ani.AccelerationRatio = AnimationAcceleration;
ani.DecelerationRatio = AnimationDeceleration;
this.BeginAnimation(MultiTransitionControl.MixProperty, ani);
}
#endregion
#region Virtuals
///
/// Called when [transition completed].
///
protected virtual void OnTransitionCompleted()
{
if (TransitionComplete != null) TransitionComplete(this);
if (SelectedControl != null)
{
Panel.SetZIndex(SelectedControl, Controls.Max(x => Panel.GetZIndex(x)) + 1);
}
if (navigationCompleteAction != null)
{
navigationCompleteAction();
navigationCompleteAction = null;
}
if (SelectedControl != null)
{
if (SelectedControl.Content is ITransitionView)
{
(SelectedControl.Content as ITransitionView).OnTransitionCompleted();
}
}
}
public interface ITransitionView
{
void OnTransitionCompleted();
}
#endregion
}
}