All the controls missing in WPF. Over 1 million downloads.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1875 lines
56 KiB

/*************************************************************************************
Extended WPF Toolkit
Copyright (C) 2007-2013 Xceed Software Inc.
This program is provided to you under the terms of the Microsoft Public
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
For more features, controls, and fast professional support,
pick up the Plus Edition at http://xceed.com/wpf_toolkit
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
***********************************************************************************/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using Xceed.Wpf.Toolkit.Media.Animation;
using Xceed.Wpf.Toolkit.Core.Utilities;
using Xceed.Wpf.Toolkit.Core;
namespace Xceed.Wpf.Toolkit.Panels
{
public abstract class AnimationPanel : PanelBase
{
#region Constructors
public AnimationPanel()
{
#if DEBUG
Type derivedType = GetType();
FieldInfo[] fields = derivedType.GetFields( BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public );
foreach( FieldInfo field in fields )
{
if( field.FieldType == typeof( DependencyProperty ) )
{
DependencyProperty prop = ( DependencyProperty )field.GetValue( null );
PropertyMetadata metaData = prop.GetMetadata( this );
if( metaData is FrameworkPropertyMetadata )
{
FrameworkPropertyMetadata frameworkData = ( FrameworkPropertyMetadata )metaData;
if( frameworkData.AffectsArrange == true || frameworkData.AffectsMeasure == true ||
frameworkData.AffectsParentArrange == true || frameworkData.AffectsParentMeasure == true )
{
System.Console.WriteLine( "AnimationPanel: " + derivedType.Name + "." + field.Name +
" - You should not set dependency property metadata flags that " +
"affect measure or arrange, instead call AnimationPanel's InvalidateMeasure or " +
"InvalidateArrange directly." );
}
}
}
}
#endif
this.Loaded += new RoutedEventHandler( this.OnLoaded );
}
#endregion
#region ChildState Private Property
private static readonly DependencyPropertyKey ChildStatePropertyKey =
DependencyProperty.RegisterAttachedReadOnly( "ChildState", typeof( ChildState ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( null ) );
private static ChildState GetChildState( DependencyObject d )
{
return ( ChildState )d.GetValue( AnimationPanel.ChildStatePropertyKey.DependencyProperty );
}
private static void SetChildState( DependencyObject d, ChildState value )
{
d.SetValue( AnimationPanel.ChildStatePropertyKey, value );
}
#endregion
#region DefaultAnimationRate Property
public static readonly DependencyProperty DefaultAnimationRateProperty =
DependencyProperty.Register( "DefaultAnimationRate", typeof( AnimationRate ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( ( AnimationRate )1d ),
new ValidateValueCallback( AnimationPanel.ValidateDefaultAnimationRate ) );
public AnimationRate DefaultAnimationRate
{
get
{
return ( AnimationRate )this.GetValue( AnimationPanel.DefaultAnimationRateProperty );
}
set
{
this.SetValue( AnimationPanel.DefaultAnimationRateProperty, value );
}
}
private static bool ValidateDefaultAnimationRate( object value )
{
if( ( AnimationRate )value == AnimationRate.Default )
throw new ArgumentException( ErrorMessages.GetMessage( ErrorMessages.DefaultAnimationRateAnimationRateDefault ) );
return true;
}
#endregion
#region DefaultAnimator Property
public static readonly DependencyProperty DefaultAnimatorProperty =
DependencyProperty.Register( "DefaultAnimator", typeof( IterativeAnimator ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( Animators.Linear ),
new ValidateValueCallback( AnimationPanel.ValidateDefaultAnimator ) );
public IterativeAnimator DefaultAnimator
{
get
{
return ( IterativeAnimator )this.GetValue( AnimationPanel.DefaultAnimatorProperty );
}
set
{
this.SetValue( AnimationPanel.DefaultAnimatorProperty, value );
}
}
private static bool ValidateDefaultAnimator( object value )
{
if( value == IterativeAnimator.Default )
throw new ArgumentException( ErrorMessages.GetMessage( ErrorMessages.DefaultAnimatorIterativeAnimationDefault ) );
return true;
}
#endregion
#region EnterAnimationRate Property
public static readonly DependencyProperty EnterAnimationRateProperty =
DependencyProperty.Register( "EnterAnimationRate", typeof( AnimationRate ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( AnimationRate.Default ) );
public AnimationRate EnterAnimationRate
{
get
{
return ( AnimationRate )this.GetValue( AnimationPanel.EnterAnimationRateProperty );
}
set
{
this.SetValue( AnimationPanel.EnterAnimationRateProperty, value );
}
}
#endregion
#region EnterAnimator Property
public static readonly DependencyProperty EnterAnimatorProperty =
DependencyProperty.Register( "EnterAnimator", typeof( IterativeAnimator ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( IterativeAnimator.Default ) );
public IterativeAnimator EnterAnimator
{
get
{
return ( IterativeAnimator )this.GetValue( AnimationPanel.EnterAnimatorProperty );
}
set
{
this.SetValue( AnimationPanel.EnterAnimatorProperty, value );
}
}
#endregion
#region EnterFrom Attached Property
public static readonly DependencyProperty EnterFromProperty =
DependencyProperty.RegisterAttached( "EnterFrom", typeof( Rect? ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( ( Rect? )null, FrameworkPropertyMetadataOptions.Inherits ) );
public static Rect? GetEnterFrom( DependencyObject d )
{
return ( Rect? )d.GetValue( AnimationPanel.EnterFromProperty );
}
public static void SetEnterFrom( DependencyObject d, Rect? value )
{
d.SetValue( AnimationPanel.EnterFromProperty, value );
}
#endregion
#region ExitAnimationRate Property
public static readonly DependencyProperty ExitAnimationRateProperty =
DependencyProperty.Register( "ExitAnimationRate", typeof( AnimationRate ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( AnimationRate.Default ) );
public AnimationRate ExitAnimationRate
{
get
{
return ( AnimationRate )this.GetValue( AnimationPanel.ExitAnimationRateProperty );
}
set
{
this.SetValue( AnimationPanel.ExitAnimationRateProperty, value );
}
}
#endregion
#region ExitAnimator Property
public static readonly DependencyProperty ExitAnimatorProperty =
DependencyProperty.Register( "ExitAnimator", typeof( IterativeAnimator ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( IterativeAnimator.Default ) );
public IterativeAnimator ExitAnimator
{
get
{
return ( IterativeAnimator )this.GetValue( AnimationPanel.ExitAnimatorProperty );
}
set
{
this.SetValue( AnimationPanel.ExitAnimatorProperty, value );
}
}
#endregion
#region ExitTo Attached Property
public static readonly DependencyProperty ExitToProperty =
DependencyProperty.RegisterAttached( "ExitTo", typeof( Rect? ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( ( Rect? )null, FrameworkPropertyMetadataOptions.Inherits ) );
public static Rect? GetExitTo( DependencyObject d )
{
return ( Rect? )d.GetValue( AnimationPanel.ExitToProperty );
}
public static void SetExitTo( DependencyObject d, Rect? value )
{
d.SetValue( AnimationPanel.ExitToProperty, value );
}
#endregion
#region LayoutAnimationRate Property
public static readonly DependencyProperty LayoutAnimationRateProperty =
DependencyProperty.Register( "LayoutAnimationRate", typeof( AnimationRate ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( AnimationRate.Default ) );
public AnimationRate LayoutAnimationRate
{
get
{
return ( AnimationRate )this.GetValue( AnimationPanel.LayoutAnimationRateProperty );
}
set
{
this.SetValue( AnimationPanel.LayoutAnimationRateProperty, value );
}
}
#endregion
#region LayoutAnimator Property
public static readonly DependencyProperty LayoutAnimatorProperty =
DependencyProperty.Register( "LayoutAnimator", typeof( IterativeAnimator ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( IterativeAnimator.Default ) );
public IterativeAnimator LayoutAnimator
{
get
{
return ( IterativeAnimator )this.GetValue( AnimationPanel.LayoutAnimatorProperty );
}
set
{
this.SetValue( AnimationPanel.LayoutAnimatorProperty, value );
}
}
#endregion
#region SwitchAnimationRate Property
public static readonly DependencyProperty SwitchAnimationRateProperty =
DependencyProperty.Register( "SwitchAnimationRate", typeof( AnimationRate ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( AnimationRate.Default ) );
public AnimationRate SwitchAnimationRate
{
get
{
return ( AnimationRate )this.GetValue( AnimationPanel.SwitchAnimationRateProperty );
}
set
{
this.SetValue( AnimationPanel.SwitchAnimationRateProperty, value );
}
}
#endregion
#region SwitchAnimator Property
public static readonly DependencyProperty SwitchAnimatorProperty =
DependencyProperty.Register( "SwitchAnimator", typeof( IterativeAnimator ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( IterativeAnimator.Default ) );
public IterativeAnimator SwitchAnimator
{
get
{
return ( IterativeAnimator )this.GetValue( AnimationPanel.SwitchAnimatorProperty );
}
set
{
this.SetValue( AnimationPanel.SwitchAnimatorProperty, value );
}
}
#endregion
#region SwitchParent Property
private static readonly DependencyPropertyKey SwitchParentPropertyKey =
DependencyProperty.RegisterReadOnly( "SwitchParent", typeof( SwitchPanel ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( null,
new PropertyChangedCallback( AnimationPanel.OnSwitchParentChanged ) ) );
public static readonly DependencyProperty SwitchParentProperty = AnimationPanel.SwitchParentPropertyKey.DependencyProperty;
public SwitchPanel SwitchParent
{
get
{
return ( SwitchPanel )this.GetValue( AnimationPanel.SwitchParentProperty );
}
}
protected internal void SetSwitchParent( SwitchPanel value )
{
this.SetValue( AnimationPanel.SwitchParentPropertyKey, value );
}
private static void OnSwitchParentChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
( ( AnimationPanel )d ).OnSwitchParentChanged( e );
}
protected virtual void OnSwitchParentChanged( DependencyPropertyChangedEventArgs e )
{
_switchParent = e.NewValue as SwitchPanel;
}
#endregion
#region SwitchTemplate Property
public static readonly DependencyProperty SwitchTemplateProperty =
DependencyProperty.Register( "SwitchTemplate", typeof( DataTemplate ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( null,
new PropertyChangedCallback( AnimationPanel.OnSwitchTemplateChanged ) ) );
public DataTemplate SwitchTemplate
{
get
{
return ( DataTemplate )this.GetValue( AnimationPanel.SwitchTemplateProperty );
}
set
{
this.SetValue( AnimationPanel.SwitchTemplateProperty, value );
}
}
private static void OnSwitchTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
( ( AnimationPanel )d ).OnSwitchTemplateChanged( e );
}
protected virtual void OnSwitchTemplateChanged( DependencyPropertyChangedEventArgs e )
{
if( _switchParent != null && _switchParent.ActiveLayout == this )
{
_switchParent.UpdateSwitchTemplate();
}
}
#endregion
#region TemplateAnimationRate Property
public static readonly DependencyProperty TemplateAnimationRateProperty =
DependencyProperty.Register( "TemplateAnimationRate", typeof( AnimationRate ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( AnimationRate.Default ) );
public AnimationRate TemplateAnimationRate
{
get
{
return ( AnimationRate )this.GetValue( AnimationPanel.TemplateAnimationRateProperty );
}
set
{
this.SetValue( AnimationPanel.TemplateAnimationRateProperty, value );
}
}
#endregion
#region TemplateAnimator Property
public static readonly DependencyProperty TemplateAnimatorProperty =
DependencyProperty.Register( "TemplateAnimator", typeof( IterativeAnimator ), typeof( AnimationPanel ),
new FrameworkPropertyMetadata( IterativeAnimator.Default ) );
public IterativeAnimator TemplateAnimator
{
get
{
return ( IterativeAnimator )this.GetValue( AnimationPanel.TemplateAnimatorProperty );
}
set
{
this.SetValue( AnimationPanel.TemplateAnimatorProperty, value );
}
}
#endregion
#region DesiredSize Property
public new Size DesiredSize
{
get
{
return ( _switchParent != null ) ? _switchParent.DesiredSize : base.DesiredSize;
}
}
#endregion
#region RenderSize Property
public new Size RenderSize
{
get
{
return ( _switchParent != null ) ? _switchParent.RenderSize : base.RenderSize;
}
set
{
base.RenderSize = value;
}
}
#endregion
#region IsActiveLayout Property
public bool IsActiveLayout
{
get
{
return _cacheBits[ ( int )CacheBits.IsActiveLayout ];
}
private set
{
_cacheBits[ ( int )CacheBits.IsActiveLayout ] = value;
}
}
#endregion
#region InternalChildren Protected Property
protected internal new UIElementCollection InternalChildren
{
get
{
return ( _switchParent == null ) ? base.InternalChildren : _switchParent.ChildrenInternal;
}
}
#endregion
#region VisualChildrenCount Protected Property
protected override int VisualChildrenCount
{
get
{
return this.HasLoaded ? this.InternalChildren.Count + this.ExitingChildren.Count : base.VisualChildrenCount;
}
}
#endregion
#region ChildrensParent Protected Property
protected PanelBase ChildrensParent
{
get
{
return _switchParent != null ? ( PanelBase )_switchParent : this;
}
}
#endregion
#region VisualChildrenCountInternal Internal Property
internal int VisualChildrenCountInternal
{
get
{
return this.VisualChildrenCount;
}
}
#endregion
#region PhysicalScrollOffset Internal Property
internal Vector PhysicalScrollOffset
{
get
{
return _physicalScrollOffset;
}
set
{
_physicalScrollOffset = value;
}
}
private Vector _physicalScrollOffset = new Vector();
#endregion
#region HasLoaded Internal Property
internal bool IsRemovingInternalChild
{
get
{
return _cacheBits[ ( int )CacheBits.IsRemovingInternalChild ];
}
private set
{
_cacheBits[ ( int )CacheBits.IsRemovingInternalChild ] = value;
}
}
#endregion
#region AnimatingChildCount Private Property
private int AnimatingChildCount
{
get
{
return _animatingChildCount;
}
set
{
// start the animation pump if the value goes positive
if( _animatingChildCount == 0 && value > 0 )
{
CompositionTarget.Rendering += new EventHandler( OnRendering );
RaiseAnimationBegunEvent();
}
// stop the animation pump if the value goes to 0
if( _animatingChildCount != 0 && value == 0 )
{
if( EndSwitchOnAnimationCompleted && _switchParent != null )
{
EndSwitchOnAnimationCompleted = false;
_switchParent.EndLayoutSwitch();
}
CompositionTarget.Rendering -= new EventHandler( OnRendering );
RaiseAnimationCompletedEvent();
}
_animatingChildCount = value;
}
}
private int _animatingChildCount;
#endregion
#region EndSwitchOnAnimationCompleted Private Property
private bool EndSwitchOnAnimationCompleted
{
get
{
return _cacheBits[ ( int )CacheBits.EndSwitchOnAnimationCompleted ];
}
set
{
_cacheBits[ ( int )CacheBits.EndSwitchOnAnimationCompleted ] = value;
}
}
#endregion
#region HasArranged Private Property
private bool HasArranged
{
get
{
return _cacheBits[ ( int )CacheBits.HasArranged ];
}
set
{
_cacheBits[ ( int )CacheBits.HasArranged ] = value;
}
}
#endregion
#region HasLoaded Private Property
protected bool HasLoaded
{
get
{
return _switchParent == null ? _cacheBits[ ( int )CacheBits.HasLoaded ] : _switchParent.HasLoaded;
}
private set
{
_cacheBits[ ( int )CacheBits.HasLoaded ] = value;
}
}
#endregion
#region IsSwitchInProgress Private Property
private bool IsSwitchInProgress
{
get
{
return _cacheBits[ ( int )CacheBits.IsSwitchInProgress ];
}
set
{
_cacheBits[ ( int )CacheBits.IsSwitchInProgress ] = value;
}
}
#endregion
#region ItemsOwner Private Property
private ItemsControl ItemsOwner
{
get
{
return ItemsControl.GetItemsOwner( _switchParent == null ? ( Panel )this : ( Panel )_switchParent );
}
}
#endregion
#region ExitingChildren Private Property
private List<UIElement> ExitingChildren
{
get
{
if( _switchParent != null )
return _switchParent.ExitingChildren;
if( _exitingChildren == null )
{
_exitingChildren = new List<UIElement>();
}
return _exitingChildren;
}
}
#endregion
#region AnimationBegun Event
public static readonly RoutedEvent AnimationBegunEvent =
EventManager.RegisterRoutedEvent( "AnimationBegun", RoutingStrategy.Bubble, typeof( RoutedEventHandler ), typeof( AnimationPanel ) );
public event RoutedEventHandler AnimationBegun
{
add
{
this.AddHandler( AnimationPanel.AnimationBegunEvent, value );
}
remove
{
this.RemoveHandler( AnimationPanel.AnimationBegunEvent, value );
}
}
protected RoutedEventArgs RaiseAnimationBegunEvent()
{
return AnimationPanel.RaiseAnimationBegunEvent( ( this._switchParent != null ) ? ( UIElement )this._switchParent : ( UIElement )this );
}
private static RoutedEventArgs RaiseAnimationBegunEvent( UIElement target )
{
if( target == null )
return null;
RoutedEventArgs args = new RoutedEventArgs();
args.RoutedEvent = AnimationPanel.AnimationBegunEvent;
RoutedEventHelper.RaiseEvent( target, args );
return args;
}
#endregion
#region AnimationCompleted Event
public static readonly RoutedEvent AnimationCompletedEvent =
EventManager.RegisterRoutedEvent( "AnimationCompleted", RoutingStrategy.Bubble, typeof( RoutedEventHandler ), typeof( AnimationPanel ) );
public event RoutedEventHandler AnimationCompleted
{
add
{
this.AddHandler( AnimationPanel.AnimationCompletedEvent, value );
}
remove
{
this.RemoveHandler( AnimationPanel.AnimationCompletedEvent, value );
}
}
protected RoutedEventArgs RaiseAnimationCompletedEvent()
{
return AnimationPanel.RaiseAnimationCompletedEvent( ( this._switchParent != null ) ? ( UIElement )this._switchParent : ( UIElement )this );
}
private static RoutedEventArgs RaiseAnimationCompletedEvent( UIElement target )
{
if( target == null )
return null;
RoutedEventArgs args = new RoutedEventArgs();
args.RoutedEvent = AnimationPanel.AnimationCompletedEvent;
RoutedEventHelper.RaiseEvent( target, args );
return args;
}
#endregion
#region ChildEntered Event
public static readonly RoutedEvent ChildEnteredEvent =
EventManager.RegisterRoutedEvent( "ChildEntered", RoutingStrategy.Bubble, typeof( ChildEnteredEventHandler ), typeof( AnimationPanel ) );
public event ChildEnteredEventHandler ChildEntered
{
add
{
this.AddHandler( AnimationPanel.ChildEnteredEvent, value );
}
remove
{
this.RemoveHandler( AnimationPanel.ChildEnteredEvent, value );
}
}
protected ChildEnteredEventArgs RaiseChildEnteredEvent( UIElement child, Rect arrangeRect )
{
return AnimationPanel.RaiseChildEnteredEvent( this, child, arrangeRect );
}
internal static ChildEnteredEventArgs RaiseChildEnteredEvent( UIElement target, UIElement child, Rect arrangeRect )
{
if( target == null )
return null;
ChildEnteredEventArgs args = new ChildEnteredEventArgs( child, arrangeRect );
args.RoutedEvent = AnimationPanel.ChildEnteredEvent;
RoutedEventHelper.RaiseEvent( target, args );
return args;
}
#endregion
#region ChildEntering Event
public static readonly RoutedEvent ChildEnteringEvent =
EventManager.RegisterRoutedEvent( "ChildEntering", RoutingStrategy.Bubble, typeof( ChildEnteringEventHandler ), typeof( AnimationPanel ) );
public event ChildEnteringEventHandler ChildEntering
{
add
{
this.AddHandler( AnimationPanel.ChildEnteringEvent, value );
}
remove
{
this.RemoveHandler( AnimationPanel.ChildEnteringEvent, value );
}
}
protected ChildEnteringEventArgs RaiseChildEnteringEvent( UIElement child, Rect? EnterFrom, Rect ArrangeRect )
{
return AnimationPanel.RaiseChildEnteringEvent( this, child, EnterFrom, ArrangeRect );
}
private static ChildEnteringEventArgs RaiseChildEnteringEvent( UIElement target, UIElement child, Rect? EnterFrom, Rect ArrangeRect )
{
if( target == null )
return null;
ChildEnteringEventArgs args = new ChildEnteringEventArgs( child, EnterFrom, ArrangeRect );
args.RoutedEvent = AnimationPanel.ChildEnteringEvent;
RoutedEventHelper.RaiseEvent( target, args );
return args;
}
#endregion
#region ChildExited Event
public static readonly RoutedEvent ChildExitedEvent =
EventManager.RegisterRoutedEvent( "ChildExited", RoutingStrategy.Bubble, typeof( ChildExitedEventHandler ), typeof( AnimationPanel ) );
public event ChildExitedEventHandler ChildExited
{
add
{
this.AddHandler( AnimationPanel.ChildExitedEvent, value );
}
remove
{
this.RemoveHandler( AnimationPanel.ChildExitedEvent, value );
}
}
protected ChildExitedEventArgs RaiseChildExitedEvent( UIElement child )
{
return AnimationPanel.RaiseChildExitedEvent( this, child );
}
private static ChildExitedEventArgs RaiseChildExitedEvent( UIElement target, UIElement child )
{
if( target == null )
return null;
ChildExitedEventArgs args = new ChildExitedEventArgs( child );
args.RoutedEvent = AnimationPanel.ChildExitedEvent;
RoutedEventHelper.RaiseEvent( target, args );
return args;
}
#endregion
#region ChildExiting Event
public static readonly RoutedEvent ChildExitingEvent =
EventManager.RegisterRoutedEvent( "ChildExiting", RoutingStrategy.Bubble, typeof( ChildExitingEventHandler ), typeof( AnimationPanel ) );
public event ChildExitingEventHandler ChildExiting
{
add
{
this.AddHandler( AnimationPanel.ChildExitingEvent, value );
}
remove
{
this.RemoveHandler( AnimationPanel.ChildExitingEvent, value );
}
}
protected ChildExitingEventArgs RaiseChildExitingEvent( UIElement child, Rect? exitTo, Rect arrangeRect )
{
return AnimationPanel.RaiseChildExitingEvent( this, child, exitTo, arrangeRect );
}
private static ChildExitingEventArgs RaiseChildExitingEvent( UIElement target, UIElement child, Rect? exitTo, Rect arrangeRect )
{
if( target == null )
return null;
ChildExitingEventArgs args = new ChildExitingEventArgs( child, exitTo, arrangeRect );
args.RoutedEvent = AnimationPanel.ChildExitingEvent;
RoutedEventHelper.RaiseEvent( target, args );
return args;
}
#endregion
#region SwitchLayoutActivated Event
public static readonly RoutedEvent SwitchLayoutActivatedEvent =
EventManager.RegisterRoutedEvent( "SwitchLayoutActivated", RoutingStrategy.Direct, typeof( RoutedEventHandler ), typeof( AnimationPanel ) );
public event RoutedEventHandler SwitchLayoutActivated
{
add
{
this.AddHandler( AnimationPanel.SwitchLayoutActivatedEvent, value );
}
remove
{
this.RemoveHandler( AnimationPanel.SwitchLayoutActivatedEvent, value );
}
}
protected RoutedEventArgs RaiseSwitchLayoutActivatedEvent()
{
return AnimationPanel.RaiseSwitchLayoutActivatedEvent( this );
}
internal static RoutedEventArgs RaiseSwitchLayoutActivatedEvent( UIElement target )
{
if( target == null )
return null;
RoutedEventArgs args = new RoutedEventArgs();
args.RoutedEvent = AnimationPanel.SwitchLayoutActivatedEvent;
RoutedEventHelper.RaiseEvent( target, args );
return args;
}
#endregion
#region SwitchLayoutDeactivated Event
public static readonly RoutedEvent SwitchLayoutDeactivatedEvent =
EventManager.RegisterRoutedEvent( "SwitchLayoutDeactivated", RoutingStrategy.Direct, typeof( RoutedEventHandler ), typeof( AnimationPanel ) );
public event RoutedEventHandler SwitchLayoutDeactivated
{
add
{
this.AddHandler( AnimationPanel.SwitchLayoutDeactivatedEvent, value );
}
remove
{
this.RemoveHandler( AnimationPanel.SwitchLayoutDeactivatedEvent, value );
}
}
protected RoutedEventArgs RaiseSwitchLayoutDeactivatedEvent()
{
return AnimationPanel.RaiseSwitchLayoutDeactivatedEvent( this );
}
internal static RoutedEventArgs RaiseSwitchLayoutDeactivatedEvent( UIElement target )
{
if( target == null )
return null;
RoutedEventArgs args = new RoutedEventArgs();
args.RoutedEvent = AnimationPanel.SwitchLayoutDeactivatedEvent;
RoutedEventHelper.RaiseEvent( target, args );
return args;
}
#endregion
public new void InvalidateArrange()
{
if( _switchParent == null )
{
base.InvalidateArrange();
}
else
{
_switchParent.InvalidateArrange();
}
}
public new void InvalidateMeasure()
{
if( _switchParent == null )
{
base.InvalidateMeasure();
}
else
{
_switchParent.InvalidateMeasure();
}
}
public new void InvalidateVisual()
{
if( _switchParent == null )
{
base.InvalidateVisual();
}
else
{
_switchParent.InvalidateVisual();
}
}
internal void ActivateLayout()
{
this.HasArranged = false;
this.IsActiveLayout = true;
this.OnSwitchLayoutActivated();
this.RaiseSwitchLayoutActivatedEvent();
}
internal void BeginChildExit( UIElement child )
{
ChildState state = AnimationPanel.GetChildState( child );
if( state != null )
{
state.Type = AnimationType.Exit;
state.HasExitBegun = true;
this.ExitingChildren.Add( child );
if( _switchParent != null )
{
_switchParent.AddVisualChildInternal( child );
}
else
{
this.AddVisualChild( child );
}
// raise the ChildExiting event only after the child has been re-added to the visual tree
ChildExitingEventArgs ceea = AnimationPanel.RaiseChildExitingEvent( child, child, AnimationPanel.GetExitTo( child ), state.CurrentPlacement );
// begin the exit animation, if necessary
state.Animator = this.GetEffectiveAnimator( AnimationType.Exit );
if( state.Animator != null )
{
state.TargetPlacement = ceea.ExitTo.HasValue ? ceea.ExitTo.Value : Rect.Empty;
state.BeginTimeStamp = DateTime.Now;
// decrement the animating count if this child is already animating because the
// ArrangeChild call will increment it again
if( state.IsAnimating )
{
this.AnimatingChildCount--;
}
this.ArrangeChild( child, state.TargetPlacement );
}
else
{
// no animation, so immediately end the exit routine
this.EndChildExit( child, state );
}
}
}
internal void BeginGrandchildAnimation( FrameworkElement grandchild, Rect currentRect, Rect placementRect )
{
bool isDone = true;
object placementArgs;
ChildState state = new ChildState( currentRect );
AnimationPanel.SetChildState( grandchild, state );
state.Type = AnimationType.Switch;
state.BeginTimeStamp = DateTime.Now;
state.TargetPlacement = placementRect;
state.Animator = this.GetEffectiveAnimator( AnimationType.Template );
if( state.Animator != null && !state.TargetPlacement.IsEmpty )
{
AnimationRate rate = this.GetEffectiveAnimationRate( AnimationType.Template );
state.CurrentPlacement = state.Animator.GetInitialChildPlacement( grandchild, state.CurrentPlacement, state.TargetPlacement, this, ref rate, out placementArgs, out isDone );
state.AnimationRate = rate;
state.PlacementArgs = placementArgs;
}
state.IsAnimating = !isDone;
grandchild.Arrange( state.IsAnimating ? state.CurrentPlacement : state.TargetPlacement );
if( state.IsAnimating )
{
_animatingGrandchildren.Add( grandchild );
this.AnimatingChildCount++;
}
else
{
state.CurrentPlacement = state.TargetPlacement;
}
}
internal void DeactivateLayout()
{
this.IsActiveLayout = false;
this.AnimatingChildCount = 0;
this.OnSwitchLayoutDeactivated();
this.RaiseSwitchLayoutDeactivatedEvent();
}
internal static UIElement FindAncestorChildOfAnimationPanel( DependencyObject element, out AnimationPanel panel )
{
panel = null;
if( element == null )
return null;
DependencyObject parent = VisualTreeHelper.GetParent( element );
if( parent == null )
return null;
if( parent is AnimationPanel || parent is SwitchPanel )
{
panel = ( parent is SwitchPanel )
? ( parent as SwitchPanel )._currentLayoutPanel
: parent as AnimationPanel;
return element as UIElement;
}
return AnimationPanel.FindAncestorChildOfAnimationPanel( parent, out panel );
}
internal Dictionary<string, Rect> GetNewLocationsBasedOnTargetPlacement( SwitchPresenter presenter, UIElement parent )
{
ChildState state = AnimationPanel.GetChildState( parent );
// if necessary, temporarily arrange the element at its final placement
bool rearrange = ( state.CurrentPlacement != state.TargetPlacement && state.IsAnimating );
if( rearrange )
{
parent.Arrange( state.TargetPlacement );
}
// now create a dictionary of locations for ID'd elements
Dictionary<string, Rect> result = new Dictionary<string, Rect>();
foreach( KeyValuePair<string, FrameworkElement> entry in presenter._knownIDs )
{
Size size = entry.Value.RenderSize;
Point[] points = { new Point(), new Point( size.Width, size.Height ) };
( entry.Value.TransformToAncestor( VisualTreeHelper.GetParent( entry.Value ) as Visual ) as MatrixTransform ).Matrix.Transform( points );
result[ entry.Key ] = new Rect( points[ 0 ], points[ 1 ] );
}
// restore the current placement
if( rearrange )
{
parent.Arrange( state.CurrentPlacement );
}
return result;
}
internal Visual GetVisualChildInternal( int index )
{
return this.GetVisualChild( index );
}
internal void OnNotifyVisualChildAddedInternal( UIElement child )
{
this.OnNotifyVisualChildAdded( child );
}
internal void OnNotifyVisualChildRemovedInternal( UIElement child )
{
this.OnNotifyVisualChildRemoved( child );
}
internal Size MeasureChildrenCore( UIElementCollection children, Size constraint )
{
_currentChildren = children;
return MeasureChildrenOverride( _currentChildren, constraint );
}
internal Size ArrangeChildrenCore( UIElementCollection children, Size finalSize )
{
if( _currentChildren != children )
{
_currentChildren = children;
}
// always reset the animating children count at the beginning of an arrange
this.AnimatingChildCount = 0;
_animatingGrandchildren.Clear();
Size result;
try
{
// determine if this arrange represents a layout switch for a SwitchPanel
if( !this.HasArranged && _switchParent != null )
{
this.IsSwitchInProgress = true;
_switchParent.BeginLayoutSwitch();
}
// arrange active children
result = this.ArrangeChildrenOverride( _currentChildren, finalSize );
// also arrange exiting children, if necessary
if( this.ExitingChildren.Count > 0 )
{
this.AnimatingChildCount += this.ExitingChildren.Count;
this.UpdateExitingChildren();
}
// if this is a layout switch, make sure the switch is ended
if( this.IsSwitchInProgress )
{
if( this.AnimatingChildCount == 0 )
{
_switchParent.EndLayoutSwitch();
}
else
{
this.EndSwitchOnAnimationCompleted = true;
}
}
}
finally
{
this.HasArranged = true;
this.IsSwitchInProgress = false;
}
return result;
}
internal void OnSwitchParentVisualChildrenChanged( DependencyObject visualAdded, DependencyObject visualRemoved )
{
this.OnVisualChildrenChanged( visualAdded, visualRemoved );
}
protected sealed override Size MeasureOverride( Size constraint )
{
return this.MeasureChildrenCore( InternalChildren, constraint );
}
protected abstract Size MeasureChildrenOverride( UIElementCollection children, Size constraint );
protected sealed override Size ArrangeOverride( Size finalSize )
{
return this.ArrangeChildrenCore( _currentChildren, finalSize );
}
protected abstract Size ArrangeChildrenOverride( UIElementCollection children, Size finalSize );
protected void ArrangeChild( UIElement child, Rect placementRect )
{
// Offset in case SwitchPanel is handling scroll.
if( placementRect.IsEmpty == false && this.PhysicalScrollOffset.Length > 0 )
{
placementRect.Offset( -this.PhysicalScrollOffset );
}
// cannot start animations unless the panel is loaded
if( this.HasLoaded )
{
if( this.BeginChildAnimation( child, placementRect ) )
{
this.AnimatingChildCount++;
}
}
else
{
// just arrange the child if the panel has not yet loaded
child.Arrange( placementRect );
}
}
protected new void AddVisualChild( Visual child )
{
if( _switchParent == null )
{
base.AddVisualChild( child );
}
else
{
_switchParent.AddVisualChildInternal( child );
}
}
protected override Visual GetVisualChild( int index )
{
if( index < 0 )
{
throw new IndexOutOfRangeException();
}
if( index >= this.InternalChildren.Count )
{
int exitIndex = index - this.InternalChildren.Count;
if( exitIndex < 0 || exitIndex >= this.ExitingChildren.Count )
throw new IndexOutOfRangeException();
return this.ExitingChildren[ exitIndex ];
}
return ( _switchParent == null ) ? base.GetVisualChild( index ) : _switchParent.GetVisualChildInternal( index );
}
protected virtual void OnNotifyVisualChildAdded( UIElement child )
{
}
protected virtual void OnNotifyVisualChildRemoved( UIElement child )
{
}
protected virtual void OnSwitchLayoutActivated()
{
}
protected virtual void OnSwitchLayoutDeactivated()
{
}
protected override void OnVisualChildrenChanged( DependencyObject visualAdded, DependencyObject visualRemoved )
{
if( !this.IsRemovingInternalChild )
{
if( visualRemoved is UIElement && visualRemoved != null )
{
this.IsRemovingInternalChild = true;
try
{
this.BeginChildExit( visualRemoved as UIElement );
}
finally
{
this.IsRemovingInternalChild = false;
}
}
}
if( _switchParent == null )
{
// The OnNotifyChildAdded/Removed methods get called for all animation panels within a
// SwitchPanel.Layouts collection, regardless of whether they are the active layout
// for the SwitchPanel. Here, we also ensure that the methods are called for standalone panels.
if( visualAdded is UIElement )
{
this.OnNotifyVisualChildAdded( visualAdded as UIElement );
}
else if( visualRemoved is UIElement )
{
this.OnNotifyVisualChildRemoved( visualRemoved as UIElement );
}
base.OnVisualChildrenChanged( visualAdded, visualRemoved );
}
else
{
_switchParent.OnVisualChildrenChangedInternal( visualAdded, visualRemoved );
}
}
protected new void RemoveVisualChild( Visual child )
{
if( _switchParent == null )
{
base.RemoveVisualChild( child );
}
else
{
_switchParent.RemoveVisualChildInternal( child );
}
}
protected int FindChildFromVisual( Visual vis )
{
int index = -1;
DependencyObject parent = vis;
DependencyObject child = null;
do
{
child = parent;
parent = VisualTreeHelper.GetParent( child );
}
while( parent != null && parent != ChildrensParent );
if( parent == this.ChildrensParent )
{
index = this.ChildrensParent.Children.IndexOf( ( UIElement )child );
}
return index;
}
private bool BeginChildAnimation( UIElement child, Rect placementRect )
{
// a private attached property is used to hold the information needed
// to calculate the location of items on subsequent frame refreshes
bool newStateCreated;
ChildState state = this.EnsureChildState( child, placementRect, out newStateCreated );
if( state.HasEnterCompleted )
{
if( state.Type != AnimationType.Exit )
{
state.BeginTimeStamp = DateTime.Now;
state.Type = IsSwitchInProgress ? AnimationType.Switch : AnimationType.Layout;
state.TargetPlacement = placementRect;
}
}
else
{
// if the child is in the middle of an enter animation, we
// still need to update the placement rect
state.BeginTimeStamp = DateTime.Now;
state.TargetPlacement = placementRect;
}
if( !state.HasExitCompleted )
{
bool isDone = true;
object placementArgs;
if( state.Type != AnimationType.Enter )
{
state.Animator = this.GetEffectiveAnimator( state.Type );
}
if( state.Animator != null && !state.TargetPlacement.IsEmpty )
{
AnimationRate rate = this.GetEffectiveAnimationRate( state.Type );
state.CurrentPlacement = state.Animator.GetInitialChildPlacement(
child, state.CurrentPlacement, state.TargetPlacement, this,
ref rate, out placementArgs, out isDone );
state.AnimationRate = rate;
state.PlacementArgs = placementArgs;
}
state.IsAnimating = !isDone;
if( !state.IsAnimating )
{
state.CurrentPlacement = state.TargetPlacement;
}
}
// JZ this might not be needed nice the OnRender will arrange
if( state.IsAnimating == false )
{
this.UpdateTrueArrange( child, state );
}
return state.IsAnimating;
}
private void BeginChildEnter( UIElement child, ChildState state )
{
state.Type = AnimationType.Enter;
// raise the ChildEntering event
ChildEnteringEventArgs ceea = AnimationPanel.RaiseChildEnteringEvent( child,
child, GetEnterFrom( child ), state.CurrentPlacement );
// begin the enter animation, if necessary
state.Animator = this.GetEffectiveAnimator( AnimationType.Enter );
if( state.Animator != null && ceea.EnterFrom.HasValue )
{
state.CurrentPlacement = ceea.EnterFrom.Value;
state.BeginTimeStamp = DateTime.Now;
}
}
private void EndChildEnter( UIElement child, ChildState state )
{
// raise the ChildExited event
state.HasEnterCompleted = true;
AnimationPanel.RaiseChildEnteredEvent( child, child, state.TargetPlacement );
}
private void EndChildExit( UIElement child, ChildState state )
{
// raise the ChildExited event
state.HasExitCompleted = true;
AnimationPanel.RaiseChildExitedEvent( child, child );
// remove the visual child relationship
if( this.ExitingChildren.Contains( child ) )
{
this.IsRemovingInternalChild = true;
try
{
if( _switchParent != null )
{
_switchParent.RemoveVisualChildInternal( child );
}
else
{
this.RemoveVisualChild( child );
}
}
finally
{
this.IsRemovingInternalChild = false;
}
this.ExitingChildren.Remove( child );
}
child.ClearValue( AnimationPanel.ChildStatePropertyKey );
}
private ChildState EnsureChildState( UIElement child, Rect placementRect, out bool newStateCreated )
{
newStateCreated = false;
ChildState state = AnimationPanel.GetChildState( child );
if( state == null )
{
// if this is null, it's because this is the first time that
// the object has been arranged
state = new ChildState( placementRect );
AnimationPanel.SetChildState( child, state );
this.BeginChildEnter( child, state );
newStateCreated = true;
}
return state;
}
internal AnimationRate GetEffectiveAnimationRate( AnimationType animationType )
{
AnimationRate result = ( _switchParent == null ) ? this.DefaultAnimationRate : _switchParent.DefaultAnimationRate;
switch( animationType )
{
case AnimationType.Enter:
if( this.EnterAnimationRate != AnimationRate.Default )
{
result = this.EnterAnimationRate;
}
else if( _switchParent != null && _switchParent.EnterAnimationRate != AnimationRate.Default )
{
result = _switchParent.EnterAnimationRate;
}
break;
case AnimationType.Exit:
if( this.ExitAnimationRate != AnimationRate.Default )
{
result = this.ExitAnimationRate;
}
else if( _switchParent != null && _switchParent.ExitAnimationRate != AnimationRate.Default )
{
result = _switchParent.ExitAnimationRate;
}
break;
case AnimationType.Layout:
if( this.LayoutAnimationRate != AnimationRate.Default )
{
result = LayoutAnimationRate;
}
else if( _switchParent != null && _switchParent.LayoutAnimationRate != AnimationRate.Default )
{
result = _switchParent.LayoutAnimationRate;
}
break;
case AnimationType.Switch:
if( this.SwitchAnimationRate != AnimationRate.Default )
{
result = SwitchAnimationRate;
}
else if( _switchParent != null && _switchParent.SwitchAnimationRate != AnimationRate.Default )
{
result = _switchParent.SwitchAnimationRate;
}
break;
case AnimationType.Template:
if( this.TemplateAnimationRate != AnimationRate.Default )
{
result = this.TemplateAnimationRate;
}
else if( _switchParent != null && _switchParent.TemplateAnimationRate != AnimationRate.Default )
{
result = _switchParent.TemplateAnimationRate;
}
break;
}
return result;
}
private IterativeAnimator GetEffectiveAnimator( AnimationType animationType )
{
IterativeAnimator result = ( _switchParent == null ) ? this.DefaultAnimator : _switchParent.DefaultAnimator;
switch( animationType )
{
case AnimationType.Enter:
if( this.EnterAnimator != IterativeAnimator.Default || ( _switchParent != null && _switchParent.EnterAnimator != IterativeAnimator.Default ) )
{
result = ( EnterAnimator == IterativeAnimator.Default ) ? _switchParent.EnterAnimator : EnterAnimator;
}
break;
case AnimationType.Exit:
if( this.ExitAnimator != IterativeAnimator.Default || ( _switchParent != null && _switchParent.ExitAnimator != IterativeAnimator.Default ) )
{
result = ( ExitAnimator == IterativeAnimator.Default ) ? _switchParent.ExitAnimator : ExitAnimator;
}
break;
case AnimationType.Layout:
if( this.LayoutAnimator != IterativeAnimator.Default || ( _switchParent != null && _switchParent.LayoutAnimator != IterativeAnimator.Default ) )
{
result = ( LayoutAnimator == IterativeAnimator.Default ) ? _switchParent.LayoutAnimator : LayoutAnimator;
}
break;
case AnimationType.Switch:
if( _switchParent != null && !_switchParent.AreLayoutSwitchesAnimated )
{
result = null;
}
else
{
if( this.SwitchAnimator != IterativeAnimator.Default || _switchParent.SwitchAnimator != IterativeAnimator.Default )
{
result = ( SwitchAnimator == IterativeAnimator.Default ) ? _switchParent.SwitchAnimator : SwitchAnimator;
}
}
break;
case AnimationType.Template:
if( this.TemplateAnimator != IterativeAnimator.Default || ( _switchParent != null && _switchParent.TemplateAnimator != IterativeAnimator.Default ) )
{
result = ( TemplateAnimator == IterativeAnimator.Default ) ? _switchParent.TemplateAnimator : TemplateAnimator;
}
break;
}
return result;
}
private void OnLoaded( object sender, RoutedEventArgs e )
{
this.HasLoaded = true;
// invalidate arrange to give enter animations a chance to run
this.InvalidateArrange();
}
private void OnRendering( object sender, EventArgs e )
{
if( !this.IsActiveLayout )
return;
if( _currentChildren != null )
{
foreach( UIElement child in _currentChildren )
{
if( child == null )
continue;
ChildState state = AnimationPanel.GetChildState( child );
if( state != null )
{
TimeSpan t = DateTime.Now.Subtract( state.BeginTimeStamp );
if( state.IsAnimating )
{
bool isDone;
state.CurrentPlacement = state.Animator.GetNextChildPlacement( child, t, state.CurrentPlacement,
state.TargetPlacement, this, state.AnimationRate, ref state.PlacementArgs, out isDone );
state.IsAnimating = !isDone;
this.UpdateTrueArrange( child, state );
if( !state.IsAnimating )
{
this.AnimatingChildCount--;
}
}
}
}
}
foreach( FrameworkElement grandchild in _animatingGrandchildren )
{
ChildState state = AnimationPanel.GetChildState( grandchild );
if( state != null && state.IsAnimating )
{
TimeSpan t = DateTime.Now.Subtract( state.BeginTimeStamp );
bool isDone;
state.CurrentPlacement = state.Animator.GetNextChildPlacement( grandchild, t, state.CurrentPlacement,
state.TargetPlacement, this, state.AnimationRate, ref state.PlacementArgs, out isDone );
state.IsAnimating = !isDone;
Rect rect = state.IsAnimating ? state.CurrentPlacement : state.TargetPlacement;
grandchild.Arrange( rect );
if( !state.IsAnimating )
{
this.AnimatingChildCount--;
}
}
}
this.UpdateExitingChildren();
if( this.AnimatingChildCount == 0 )
{
_animatingGrandchildren.Clear();
}
}
private void UpdateExitingChildren()
{
if( this.ExitingChildren.Count > 0 )
{
List<UIElement> exitingChildren = new List<UIElement>( ExitingChildren );
foreach( UIElement child in exitingChildren )
{
if( child == null )
continue;
ChildState state = AnimationPanel.GetChildState( child );
if( state != null )
{
TimeSpan t = DateTime.Now.Subtract( state.BeginTimeStamp );
if( state.IsAnimating )
{
bool isDone;
state.CurrentPlacement = state.Animator.GetNextChildPlacement( child, t, state.CurrentPlacement,
state.TargetPlacement, this, state.AnimationRate, ref state.PlacementArgs, out isDone );
state.IsAnimating = !isDone;
this.UpdateTrueArrange( child, state );
if( !state.IsAnimating )
{
this.AnimatingChildCount--;
}
}
}
}
}
}
private void UpdateTrueArrange( UIElement child, ChildState state )
{
if( !state.TargetPlacement.IsEmpty )
{
child.Arrange( state.IsAnimating && state.Animator != null ? state.CurrentPlacement : state.TargetPlacement );
}
// if the child is done entering, complete the enter routine
if( !state.IsAnimating && !state.HasEnterCompleted )
{
this.EndChildEnter( child, state );
}
// if the child is done exiting, complete the exit routine
if( !state.IsAnimating && state.HasExitBegun )
{
this.EndChildExit( child, state );
}
}
#region Private Fields
private UIElementCollection _currentChildren;
private readonly Collection<FrameworkElement> _animatingGrandchildren = new Collection<FrameworkElement>();
private SwitchPanel _switchParent = null;
private List<UIElement> _exitingChildren = null;
private BitVector32 _cacheBits = new BitVector32( 1 );
#endregion
#region ChildState Nested Type
private sealed class ChildState
{
public ChildState( Rect currentRect )
{
this.CurrentPlacement = currentRect;
this.TargetPlacement = currentRect;
this.BeginTimeStamp = DateTime.Now;
}
public bool HasEnterCompleted
{
get
{
return _cacheBits[ ( int )CacheBits.HasEnterCompleted ];
}
set
{
_cacheBits[ ( int )CacheBits.HasEnterCompleted ] = value;
}
}
public bool HasExitBegun
{
get
{
return _cacheBits[ ( int )CacheBits.HasExitBegun ];
}
set
{
_cacheBits[ ( int )CacheBits.HasExitBegun ] = value;
}
}
public bool HasExitCompleted
{
get
{
return _cacheBits[ ( int )CacheBits.HasExitCompleted ];
}
set
{
_cacheBits[ ( int )CacheBits.HasExitCompleted ] = value;
}
}
public bool IsAnimating
{
get
{
return _cacheBits[ ( int )CacheBits.IsAnimating ];
}
set
{
_cacheBits[ ( int )CacheBits.IsAnimating ] = value;
}
}
public AnimationType Type;
public DateTime BeginTimeStamp;
public IterativeAnimator Animator;
public Rect CurrentPlacement;
public Rect TargetPlacement;
public AnimationRate AnimationRate;
public object PlacementArgs;
private BitVector32 _cacheBits = new BitVector32( 0 );
private enum CacheBits
{
IsAnimating = 0x00000001,
HasEnterCompleted = 0x00000002,
HasExitBegun = 0x00000004,
HasExitCompleted = 0x00000008,
}
}
#endregion
#region AnimationType Nested Type
internal enum AnimationType
{
Enter,
Exit,
Layout,
Switch,
Template,
}
#endregion
#region CacheBits Nested Type
private enum CacheBits
{
IsActiveLayout = 0x00000001,
IsSwitchInProgress = 0x00000002,
EndSwitchOnAnimationCompleted = 0x00000010,
IsRemovingInternalChild = 0x00000020,
HasLoaded = 0x00000040,
HasArranged = 0x00000080,
}
#endregion
}
}