public void BeginAnimation( DependencyProperty dp, AnimationTimeline animation, HandoffBehavior handoffBehavior) { throw new NotImplementedException(); }
/// <summary> /// Starts the specified <paramref name="board"/> in the context of the specified /// <paramref name="element"/>. /// </summary> /// <remarks> /// Depending on the parameter <paramref name="handoffBehavior"/>, the new storyboard will /// be started when the last other storyboard, which occupies a conflicting property, /// has finished. /// </remarks> /// <param name="board">The storyboard to start.</param> /// <param name="element">Context element which will be used as /// <see cref="TimelineContext.VisualParent"/> for the new <paramref name="board"/>.</param> /// <param name="handoffBehavior">Controls how the new storyboard animation will be /// attached to already running animations, if there are conflicting properties animated /// by an already running anmiation an by the new <paramref name="board"/>.</param> public void StartStoryboard(Storyboard board, UIElement element, HandoffBehavior handoffBehavior) { lock (_syncObject) { AnimationContext context = new AnimationContext { Timeline = board, TimelineContext = board.CreateTimelineContext(element) }; IDictionary <IDataDescriptor, object> conflictingProperties; ICollection <AnimationContext> conflictingAnimations; FindConflicts(context, out conflictingAnimations, out conflictingProperties); ExecuteHandoff(context, conflictingAnimations, handoffBehavior); try { board.Setup(context.TimelineContext, conflictingProperties); _scheduledAnimations.Add(context); board.Start(context.TimelineContext, SkinContext.SystemTickCount); } catch (Exception ex) { ServiceRegistration.Get <ILogger>().Error("Animator: Error initializing StoryBoard", ex); } // No animation here - has to be done in the Animate method } }
public void Begin(FrameworkElement containingObject, FrameworkTemplate frameworkTemplate, HandoffBehavior handoffBehavior, bool isControllable) { throw new NotImplementedException(); }
public void ApplyAnimationClock( DependencyProperty dp, AnimationClock clock, HandoffBehavior handoffBehavior) { throw new NotImplementedException(); }
public static void AnimateDoubleCubicEase(this UIElement target, DependencyProperty propdp, double toVal, int ms, EasingMode ease, HandoffBehavior handOff = HandoffBehavior.Compose, int begin = 0, EventHandler completed = null) { var anim = new DoubleAnimation(toVal, new Duration(TimeSpan.FromMilliseconds(ms))); switch (ease) { case EasingMode.EaseIn: anim.EasingFunction = App.CE_EaseIn; break; case EasingMode.EaseOut: anim.EasingFunction = App.CE_EaseOut; break; case EasingMode.EaseInOut: anim.EasingFunction = App.CE_EaseInOut; break; } if (begin > 0) { anim.BeginTime = TimeSpan.FromMilliseconds(begin); } if (completed != null) { anim.Completed += completed; } target.BeginAnimation(propdp, anim, handOff); }
/// <summary> /// Registers the specified animation instance. /// </summary> /// <param name="animationInstance">The animation instance.</param> /// <param name="handoffBehavior"> /// A value indicating how the new animations interact with existing ones. /// </param> /// <param name="previousInstance"> /// Optional: The animation instance after which <paramref name="animationInstance"/> will be /// added in the animation composition chain. If set to <see langword="null"/> /// <paramref name="animationInstance"/> will be appended at the end of the composition chain. /// This parameter is only relevant when <paramref name="handoffBehavior"/> is /// <see cref="HandoffBehavior.Compose"/>. /// </param> /// <remarks> /// <para> /// This method adds the specified animation tree (<paramref name="animationInstance"/> and all /// of its children) to the animation system. The animation system will from now on /// automatically advance and update the animations. /// </para> /// <para> /// Adding and removing animation instances is usually controlled by /// <see cref="AnimationTransition"/> instances. /// </para> /// </remarks> /// <exception cref="ArgumentNullException"> /// <paramref name="animationInstance" /> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentException"> /// Cannot add <paramref name="animationInstance"/> to animation system. The animation instance /// is already registered, or it is not a root instance. /// </exception> internal void Add(AnimationInstance animationInstance, HandoffBehavior handoffBehavior, AnimationInstance previousInstance) { if (animationInstance == null) { throw new ArgumentNullException("animationInstance"); } if (_rootInstances.Contains(animationInstance)) // TODO: This is slow if there are many animation instances! { throw new ArgumentException("Cannot add animation instance to animation system. The animation instance is already registered."); } if (!animationInstance.IsRoot) { throw new ArgumentException("Cannot add animation instance to animation system because it is not a root instance. You need to disconnect the instance from its parent first."); } _rootInstances.Add(animationInstance); // Normally, the time is NaN and starts to run now. (Unless the user has set a custom // time value.) if (animationInstance.Time == null) { animationInstance.Time = TimeSpan.Zero; } animationInstance.AddToCompositionChains(this, handoffBehavior, previousInstance); }
public void Begin(FrameworkElement target, HandoffBehavior handoffBehavior) { NoesisGUI_PINVOKE.Storyboard_Begin__SWIG_3(swigCPtr, FrameworkElement.getCPtr(target), (int)handoffBehavior); if (NoesisGUI_PINVOKE.SWIGPendingException.Pending) { throw NoesisGUI_PINVOKE.SWIGPendingException.Retrieve(); } }
/// <summary> /// Start animation. /// </summary> /// <param name="storyBoardName">Name of the story board.</param> /// <param name="handoffBehavior">HandoffBehavior.</param> private void _StartStoryBoardAtGrid(string storyBoardName, HandoffBehavior handoffBehavior) { // Find storyboard. Storyboard s = (Storyboard)this.FindResource(storyBoardName); // Start animation. stackPanel.BeginStoryboard(s, handoffBehavior); }
public void Begin(FrameworkElement target, FrameworkElement nameScope, HandoffBehavior handoffBehavior, bool isControllable) { NoesisGUI_PINVOKE.Storyboard_Begin__SWIG_8(swigCPtr, FrameworkElement.getCPtr(target), FrameworkElement.getCPtr(nameScope), (int)handoffBehavior, isControllable); if (NoesisGUI_PINVOKE.SWIGPendingException.Pending) { throw NoesisGUI_PINVOKE.SWIGPendingException.Retrieve(); } }
public void Begin(FrameworkElement target, HandoffBehavior handoffBehavior, bool isControllable) { if (target == null) { throw new ArgumentNullException("target"); } { NoesisGUI_PINVOKE.Storyboard_Begin__SWIG_4(swigCPtr, FrameworkElement.getCPtr(target), (int)handoffBehavior, isControllable); } }
public void StartStoryboard(Storyboard board, HandoffBehavior handoffBehavior) { Screen screen = Screen; if (screen == null) { return; } screen.Animator.StartStoryboard(board, this, handoffBehavior); }
public void Begin(FrameworkElement target, FrameworkElement nameScope, HandoffBehavior handoffBehavior) { NoesisGUI_PINVOKE.Storyboard_Begin__SWIG_7(swigCPtr, FrameworkElement.getCPtr(target), FrameworkElement.getCPtr(nameScope), (int)handoffBehavior); #if UNITY_EDITOR || NOESIS_API if (NoesisGUI_PINVOKE.SWIGPendingException.Pending) { throw NoesisGUI_PINVOKE.SWIGPendingException.Retrieve(); } #endif }
public void Begin(FrameworkElement target, HandoffBehavior handoffBehavior, bool isControllable) { NoesisGUI_PINVOKE.Storyboard_Begin__SWIG_4(swigCPtr, FrameworkElement.getCPtr(target), (int)handoffBehavior, isControllable); #if UNITY_EDITOR || NOESIS_API if (NoesisGUI_PINVOKE.SWIGPendingException.Pending) { throw NoesisGUI_PINVOKE.SWIGPendingException.Retrieve(); } #endif }
//public static void AnimateDoubleCubicEase(this Animatable target, DependencyProperty propdp, double toVal, int ms, EasingMode ease, // HandoffBehavior handOff = HandoffBehavior.Compose, int begin = 0) //{ // var anim = new DoubleAnimation(toVal, new Duration(TimeSpan.FromMilliseconds(ms))) { EasingFunction = new CubicEase { EasingMode = ease } }; // if (begin > 0) anim.BeginTime = TimeSpan.FromMilliseconds(begin); // target.BeginAnimation(propdp, anim, handOff); //} public static void AnimateBool(this UIElement target, DependencyProperty propdp, bool fromVal, bool toVal, int ms, HandoffBehavior handOff = HandoffBehavior.Compose) { var anim = new BooleanAnimationUsingKeyFrames(); if (ms > 0) { anim.KeyFrames.Add(new DiscreteBooleanKeyFrame(fromVal, KeyTime.FromTimeSpan(TimeSpan.Zero))); } anim.KeyFrames.Add(new DiscreteBooleanKeyFrame(toVal, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(ms)))); target.BeginAnimation(propdp, anim, handOff); }
[FriendAccessAllowed] // Built into Core, also used by Framework. internal static bool IsDefined(HandoffBehavior handoffBehavior) { if (handoffBehavior < HandoffBehavior.SnapshotAndReplace || handoffBehavior > HandoffBehavior.Compose) { return(false); } else { return(true); } }
[FriendAccessAllowed] // Built into Core, also used by Framework. internal static bool IsDefined( HandoffBehavior handoffBehavior ) { if( handoffBehavior < HandoffBehavior.SnapshotAndReplace || handoffBehavior > HandoffBehavior.Compose ) { return false; } else { return true; } }
public void Begin(FrameworkElement target, FrameworkElement nameScope, HandoffBehavior handoffBehavior) { if (target == null) { throw new ArgumentNullException("target"); } if (nameScope == null) { throw new ArgumentNullException("nameScope"); } { NoesisGUI_PINVOKE.Storyboard_Begin__SWIG_7(swigCPtr, FrameworkElement.getCPtr(target), FrameworkElement.getCPtr(nameScope), (int)handoffBehavior); } }
public void Begin(FrameworkElement containingObject, INameScope nameScope = null, HandoffBehavior handoffBehavior = HandoffBehavior.SnapshotAndReplace, object layerOwner = null) { Stop(containingObject); TimelineClock clock = CreateClock(); clock.Begin(((IAnimatable)containingObject).RootClock); clocks[containingObject] = clock; ListDictionary<TargetKey, AnimationTimelineClock> targets = GetAnimationClocksTargets(clock, containingObject, nameScope ?? NameScope.GetContainingNameScope(containingObject)); foreach (TargetKey target in targets.GetKeys()) { target.Target.ApplyAnimationClocks(target.TargetProperty, targets.GetValues(target), handoffBehavior, layerOwner); } }
internal static void ApplyAnimationClock( DependencyObject d, DependencyProperty dp, AnimationClock animationClock, HandoffBehavior handoffBehavior) { if (animationClock == null) { BeginAnimation(d, dp, null, handoffBehavior); } else { // Optimize to avoid allocation of potentially unneeded array. ApplyAnimationClocks(d, dp, new AnimationClock[] { animationClock }, handoffBehavior); } }
internal static void ApplyAnimationClock( DependencyObject d, DependencyProperty dp, AnimationClock animationClock, HandoffBehavior handoffBehavior) { if (animationClock == null) { BeginAnimation(d, dp, null, handoffBehavior); } else { // ApplyAnimationClocks(d, dp, new AnimationClock[] { animationClock }, handoffBehavior); } }
/// <summary> /// Handles the handoff between conflicting animations. /// This method will, depending on the specified <paramref name="handoffBehavior"/>, stop conflicting /// animations (in case see cref="HandoffBehavior.SnapshotAndReplace"/>) /// or add them to the wait set for the given <paramref name="animationContext"/> /// (in case <see cref="HandoffBehavior.Compose"/>). /// The handoff behavior <see cref="HandoffBehavior.TemporaryReplace"/> will stop the conflicting /// animations, let the new animation run, and re-schedule the conflicting animations after the new animation. /// </summary> protected void ExecuteHandoff(AnimationContext animationContext, ICollection <AnimationContext> conflictingAnimations, HandoffBehavior handoffBehavior) { // Do the handoff depending on HandoffBehavior switch (handoffBehavior) { case HandoffBehavior.Compose: foreach (AnimationContext ac in conflictingAnimations) { animationContext.WaitingFor.Add(ac); } break; case HandoffBehavior.TemporaryReplace: foreach (AnimationContext ac in conflictingAnimations) { ac.WaitingFor.Add(animationContext); } break; case HandoffBehavior.SnapshotAndReplace: // Reset values of conflicting animations foreach (AnimationContext ac in conflictingAnimations) { ResetAllValues(ac); } // And remove those values which are handled by the new animation - // avoids flickering IDictionary <IDataDescriptor, object> animProperties = new Dictionary <IDataDescriptor, object>(); animationContext.Timeline.AddAllAnimatedProperties(animationContext.TimelineContext, animProperties); foreach (IDataDescriptor dd in animProperties.Keys) { _valuesToSet.Remove(dd); } break; default: throw new NotImplementedException("Animator.HandleConflicts: HandoffBehavior '" + handoffBehavior + "' is not implemented"); } }
/// <summary> /// Applies an AnimationClock to a DependencyProperty. The effect of /// the new AnimationClock on any current animations will be determined by /// the value of the handoffBehavior parameter. /// </summary> /// <param name="dp"> /// The DependencyProperty to animate. /// </param> /// <param name="clock"> /// The AnimationClock that will animate the property. If parameter is null /// then animations will be removed from the property if handoffBehavior is /// SnapshotAndReplace; otherwise the method call will have no result. /// </param> /// <param name="handoffBehavior"> /// Determines how the new AnimationClock will transition from or /// affect any current animations on the property. /// </param> public void ApplyAnimationClock( DependencyProperty dp, AnimationClock clock, HandoffBehavior handoffBehavior) { if (dp == null) { throw new ArgumentNullException("dp"); } if (!AnimationStorage.IsPropertyAnimatable(this, dp)) { #pragma warning disable 56506 // Suppress presharp warning: Parameter 'dp' to this public method must be validated: A null-dereference can occur here. throw new ArgumentException(SR.Get(SRID.Animation_DependencyPropertyIsNotAnimatable, dp.Name, this.GetType()), "dp"); #pragma warning restore 56506 } if (clock != null && !AnimationStorage.IsAnimationValid(dp, clock.Timeline)) { #pragma warning disable 56506 // Suppress presharp warning: Parameter 'dp' to this public method must be validated: A null-dereference can occur here. throw new ArgumentException(SR.Get(SRID.Animation_AnimationTimelineTypeMismatch, clock.Timeline.GetType(), dp.Name, dp.PropertyType), "clock"); #pragma warning restore 56506 } if (!HandoffBehaviorEnum.IsDefined(handoffBehavior)) { throw new ArgumentException(SR.Get(SRID.Animation_UnrecognizedHandoffBehavior)); } if (IsSealed) { throw new InvalidOperationException(SR.Get(SRID.IAnimatable_CantAnimateSealedDO, dp, this.GetType())); } AnimationStorage.ApplyAnimationClock(this, dp, clock, handoffBehavior); }
/// <summary> /// Starts the specified <paramref name="board"/> in the context of the specified /// <paramref name="element"/>. /// </summary> /// <remarks> /// Depending on the parameter <paramref name="handoffBehavior"/>, the new storyboard will /// be started when the last other storyboard, which occupies a conflicting property, /// has finished. /// </remarks> /// <param name="board">The storyboard to start.</param> /// <param name="element">Context element which will be used as /// <see cref="TimelineContext.VisualParent"/> for the new <paramref name="board"/>.</param> /// <param name="handoffBehavior">Controls how the new storyboard animation will be /// attached to already running animations, if there are conflicting properties animated /// by an already running anmiation an by the new <paramref name="board"/>.</param> public void StartStoryboard(Storyboard board, UIElement element, HandoffBehavior handoffBehavior) { lock (_syncObject) { AnimationContext context = new AnimationContext { Timeline = board, TimelineContext = board.CreateTimelineContext(element) }; IDictionary <IDataDescriptor, object> conflictingProperties; ICollection <AnimationContext> conflictingAnimations; FindConflicts(context, out conflictingAnimations, out conflictingProperties); ExecuteHandoff(context, conflictingAnimations, handoffBehavior); board.Setup(context.TimelineContext, conflictingProperties); _scheduledAnimations.Add(context); board.Start(context.TimelineContext, SkinContext.SystemTickCount); // No animation here - has to be done in the Animate method } }
public void StartStoryboard(Storyboard board, HandoffBehavior handoffBehavior) { Screen screen = Screen; if (screen == null) return; screen.Animator.StartStoryboard(board, this, handoffBehavior); }
public void ApplyAnimationClock(System.Windows.DependencyProperty dp, AnimationClock clock, HandoffBehavior handoffBehavior) { }
/// <summary> /// Begins the given Storyboard as a Storyboard with the given handoff /// policy, and with the specified state for controllability. /// </summary> public void BeginStoryboard(Storyboard storyboard, HandoffBehavior handoffBehavior, bool isControllable) { if( storyboard == null ) { throw new ArgumentNullException("storyboard"); } // Storyboard.Begin is a public API and needs to be validating handoffBehavior anyway. storyboard.Begin( this, handoffBehavior, isControllable ); }
internal static void ApplyAnimationClocksToLayer( DependencyObject d, DependencyProperty dp, IList<AnimationClock> animationClocks, HandoffBehavior handoffBehavior, Int64 propertyTriggerLayerIndex) { if( propertyTriggerLayerIndex == 1 ) { // Layer 1 is a special layer, where it gets treated as if there // was no layer specification at all. ApplyAnimationClocks( d, dp, animationClocks, handoffBehavior ); return; } Debug.Assert(animationClocks != null); Debug.Assert(!animationClocks.Contains(null)); Debug.Assert(HandoffBehaviorEnum.IsDefined(handoffBehavior), "Public API caller of this internal method is responsible for validating that the HandoffBehavior value is valid."); AnimationStorage storage = GetStorage(d, dp); if (storage == null) { storage = CreateStorage(d, dp); } SortedList<Int64, AnimationLayer> propertyTriggerLayers = storage._propertyTriggerLayers; if (propertyTriggerLayers == null) { propertyTriggerLayers = new SortedList<Int64, AnimationLayer>(1); storage._propertyTriggerLayers = propertyTriggerLayers; } AnimationLayer layer; if (propertyTriggerLayers.ContainsKey(propertyTriggerLayerIndex)) { layer = propertyTriggerLayers[propertyTriggerLayerIndex]; } else { layer = new AnimationLayer(storage); propertyTriggerLayers[propertyTriggerLayerIndex] = layer; } object defaultDestinationValue = DependencyProperty.UnsetValue; if (handoffBehavior == HandoffBehavior.SnapshotAndReplace) { // defaultDestinationValue = ((IAnimatable)d).GetAnimationBaseValue(dp); int count = propertyTriggerLayers.Count; if (count > 1) { IList<Int64> keys = propertyTriggerLayers.Keys; for (int i = 0; i < count && keys[i] < propertyTriggerLayerIndex; i++) { AnimationLayer currentLayer; propertyTriggerLayers.TryGetValue(keys[i], out currentLayer); defaultDestinationValue = currentLayer.GetCurrentValue(defaultDestinationValue); } } } layer.ApplyAnimationClocks( animationClocks, handoffBehavior, defaultDestinationValue); storage.WritePostscript(); }
public void BeginStoryboard(Storyboard storyboard, HandoffBehavior handoffBehavior);
public void Begin(System.Windows.FrameworkElement containingObject, System.Windows.FrameworkTemplate frameworkTemplate, HandoffBehavior handoffBehavior) { }
internal void ApplyAnimationClocks( IList<AnimationClock> newAnimationClocks, HandoffBehavior handoffBehavior, object defaultDestinationValue) { Debug.Assert( newAnimationClocks == null || (newAnimationClocks.Count > 0 && !newAnimationClocks.Contains(null))); if (handoffBehavior == HandoffBehavior.SnapshotAndReplace) { Debug.Assert(defaultDestinationValue != DependencyProperty.UnsetValue, "We need a valid default destination value when peforming a snapshot and replace."); EventHandler handler = new EventHandler(OnCurrentStateInvalidated); // If we have a sticky snapshot value, the clock that would have // unstuck it is being replaced, so we need to remove our event // handler from that clock. if (_hasStickySnapshotValue) { _animationClocks[0].CurrentStateInvalidated -= handler; DetachAnimationClocks(); } // Otherwise if we have at least one clock take a new snapshot // value. else if (_animationClocks != null) { _snapshotValue = GetCurrentValue(defaultDestinationValue); DetachAnimationClocks(); } // Otherwise we can use the defaultDestinationValue as the // new snapshot value. else { _snapshotValue = defaultDestinationValue; } // If we have a new clock in a stopped state, then the snapshot // value will be sticky. if (newAnimationClocks != null && newAnimationClocks[0].CurrentState == ClockState.Stopped) { _hasStickySnapshotValue = true; newAnimationClocks[0].CurrentStateInvalidated += handler; } // Otherwise it won't be sticky. else { _hasStickySnapshotValue = false; } SetAnimationClocks(newAnimationClocks); } else { Debug.Assert(handoffBehavior == HandoffBehavior.Compose, "Unhandled handoffBehavior value."); Debug.Assert(defaultDestinationValue == DependencyProperty.UnsetValue, "We shouldn't take the time to calculate a default destination value when it isn't needed."); if (newAnimationClocks == null) { return; } else if (_animationClocks == null) { SetAnimationClocks(newAnimationClocks); } else { AppendAnimationClocks(newAnimationClocks); } } }
public void ApplyAnimationClock (DependencyProperty dp, AnimationClock clock, HandoffBehavior handoffBehavior) { throw new NotImplementedException (); }
/// <summary> /// Starts the specified <paramref name="board"/> in the context of the specified /// <paramref name="element"/>. /// </summary> /// <remarks> /// Depending on the parameter <paramref name="handoffBehavior"/>, the new storyboard will /// be started when the last other storyboard, which occupies a conflicting property, /// has finished. /// </remarks> /// <param name="board">The storyboard to start.</param> /// <param name="element">Context element which will be used as /// <see cref="TimelineContext.VisualParent"/> for the new <paramref name="board"/>.</param> /// <param name="handoffBehavior">Controls how the new storyboard animation will be /// attached to already running animations, if there are conflicting properties animated /// by an already running anmiation an by the new <paramref name="board"/>.</param> public void StartStoryboard(Storyboard board, UIElement element, HandoffBehavior handoffBehavior) { lock (_syncObject) { AnimationContext context = new AnimationContext { Timeline = board, TimelineContext = board.CreateTimelineContext(element) }; IDictionary<IDataDescriptor, object> conflictingProperties; ICollection<AnimationContext> conflictingAnimations; FindConflicts(context, out conflictingAnimations, out conflictingProperties); ExecuteHandoff(context, conflictingAnimations, handoffBehavior); try { board.Setup(context.TimelineContext, conflictingProperties); _scheduledAnimations.Add(context); board.Start(context.TimelineContext, SkinContext.SystemTickCount); } catch (Exception ex) { ServiceRegistration.Get<ILogger>().Error("Animator: Error initializing StoryBoard", ex); } // No animation here - has to be done in the Animate method } }
/// <summary> /// Begins all ControlTemplate animations underneath this storyboard, clock tree starts at the given Control. /// </summary> public void Begin( FrameworkElement containingObject, FrameworkTemplate frameworkTemplate, HandoffBehavior handoffBehavior, bool isControllable ) { BeginCommon(containingObject, frameworkTemplate, handoffBehavior, isControllable, Storyboard.Layers.Code ); }
/// <summary> /// Begins all ControlTemplate animations underneath this storyboard, clock tree starts at the given Control. /// </summary> public void Begin( FrameworkElement containingObject, FrameworkTemplate frameworkTemplate, HandoffBehavior handoffBehavior ) { Begin( containingObject, frameworkTemplate, handoffBehavior, false ); }
public void BeginAnimation (DependencyProperty dp, AnimationTimeline animation, HandoffBehavior handoffBehavior) { throw new NotImplementedException (); }
public void ApplyAnimationClock(DependencyProperty dp, AnimationClock clock, HandoffBehavior handoffBehavior);
public void BeginStoryboard(Storyboard storyboard, HandoffBehavior handoffBehavior, bool isControllable);
/// <summary> /// Takes the built up mapping table for animation clocks and applies /// them to the specified property on the specified object. /// </summary> private static void ApplyAnimationClocks( HybridDictionary clockMappings, HandoffBehavior handoffBehavior, Int64 layer ) { foreach( DictionaryEntry entry in clockMappings ) { ObjectPropertyPair key = (ObjectPropertyPair)entry.Key; object value = entry.Value; List<AnimationClock> clockList; Debug.Assert( value is AnimationClock || value is List<AnimationClock> , "Internal error - clockMappings table contains unexpected object of type" + value.GetType() ); if( value is AnimationClock ) { clockList = new List<AnimationClock>(1); clockList.Add((AnimationClock)value); } else // if( value is List<AnimationClock> ) { clockList = (List<AnimationClock>)value; } AnimationStorage.ApplyAnimationClocksToLayer( key.DependencyObject, key.DependencyProperty, clockList, handoffBehavior, layer); } }
internal static void BeginAnimation( DependencyObject d, DependencyProperty dp, AnimationTimeline animation, HandoffBehavior handoffBehavior) { // Caller should be validating animation. Debug.Assert(animation == null || IsAnimationValid(dp, animation)); Debug.Assert(IsPropertyAnimatable(d, dp)); Debug.Assert(HandoffBehaviorEnum.IsDefined(handoffBehavior), "Public API caller of this internal method is responsible for validating that the HandoffBehavior value is valid." ); AnimationStorage storage = GetStorage(d, dp); if (animation == null) { if ( storage == null || handoffBehavior == HandoffBehavior.Compose) { // Composing with a null animation is a no-op. return; } else { // When the incoming animation is passed in as null and // handoffBehavior == HandoffBehavior.SnapshotAndReplace it means // that we should stop any and all animation behavior for // this property. if (storage._hasStickySnapshotValue) { storage._hasStickySnapshotValue = false; storage._animationClocks[0].CurrentStateInvalidated -= new EventHandler(storage.OnCurrentStateInvalidated); } storage._snapshotValue = DependencyProperty.UnsetValue; storage.ClearAnimations(); } } else if (animation.BeginTime.HasValue) { // We have an animation AnimationClock animationClock; animationClock = animation.CreateClock(); // note that CreateClock also calls InternalBeginIn ApplyAnimationClocks(d, dp, new AnimationClock[] { animationClock }, handoffBehavior); // ApplyAnimationClocks has fixed up the storage and called // WritePostscript already so we can just return. return; } else if (storage == null) { // The user gave us an animation with a BeginTime of null which // means snapshot the current value and throw away all animations // for SnapshotAndReplace and means nothing for Compose. // But since we don't have any animations the current we don't // have to do anything for either of these cases. return; } else if (handoffBehavior == HandoffBehavior.SnapshotAndReplace) { // This block handles the case where the user has called // BeginAnimation with an animation that has a null begin time. // We handle this by taking a snapshot value and throwing // out the animation, which is the same as keeping it because // we know it will never start. // // If the handoffBehavior is Compose, we ignore the user's call // because it wouldn't mean anything unless they were planning // on changing the BeginTime of their animation later, which we // don't support. // If _hasStickySnapshotValue is set, unset it and remove our // event handler from the clock. The current snapshot value // will still be used. if (storage._hasStickySnapshotValue) { Debug.Assert(storage._animationClocks != null && storage._animationClocks.Count > 0, "If _hasStickySnapshotValue is set we should have at least one animation clock stored in the AnimationStorage."); storage._hasStickySnapshotValue = false; storage._animationClocks[0].CurrentStateInvalidated -= new EventHandler(storage.OnCurrentStateInvalidated); } // Otherwise take a new snapshot value. else { storage._snapshotValue = d.GetValue(dp); } storage.ClearAnimations(); } // If storage were null we would have returned already. storage.WritePostscript(); }
/// <summary> /// For complex property paths, we need to dig our way down to the /// property and attach the animation clock there. We will not be able to /// actually attach the clocks if the targetProperty points to a frozen /// Freezable. More extensive handling will be required for that case. /// </summary> private void ProcessComplexPath( HybridDictionary clockMappings, DependencyObject targetObject, PropertyPath path, AnimationClock animationClock, HandoffBehavior handoffBehavior, Int64 layer ) { Debug.Assert(path.Length > 1, "This method shouldn't even be called for a simple property path."); // For complex paths, the target object/property differs from the actual // animated object/property. // // Example: // TargetName="Rect1" TargetProperty="(Rectangle.LayoutTransform).(RotateTransform.Angle)" // // The target object is a Rectangle. // The target property is LayoutTransform. // The animated object is a RotateTransform // The animated property is Angle. // Currently unsolved problem: If the LayoutTransform is not a RotateTransform, // we have no way of knowing. We'll merrily set up to animate the Angle // property as an attached property, not knowing that the value will be // completely ignored. DependencyProperty targetProperty = path.GetAccessor(0) as DependencyProperty; // Two different ways to deal with property paths. If the target is // on a frozen Freezable, we'll have to make a clone of the value and // attach the animation on the clone instead. // For all other objects, we attach the animation clock directly on the // specified animating object and property. object targetPropertyValue = targetObject.GetValue(targetProperty); DependencyObject animatedObject = path.LastItem as DependencyObject; DependencyProperty animatedProperty = path.LastAccessor as DependencyProperty; if( animatedObject == null || animatedProperty == null || targetProperty == null ) { throw new InvalidOperationException(SR.Get(SRID.Storyboard_PropertyPathUnresolved, path.Path)); } VerifyAnimationIsValid(animatedProperty, animationClock); if( PropertyCloningRequired( targetPropertyValue ) ) { // Verify that property paths are supported for the specified // object and property. If the property value query (usually in // GetValueCore) doesn't call into Storyboard code, then none of this // will have any effect. (Silently do nothing.) // Throwing here is for user's sake to alert that nothing will happen. VerifyComplexPathSupport( targetObject ); // We need to clone the value of the target, and from here onwards // try to pretend that it is the actual value. Debug.Assert(targetPropertyValue is Freezable, "We shouldn't be trying to clone a type we don't understand. PropertyCloningRequired() has improperly flagged the current value as 'need to clone'."); // To enable animations on frozen Freezable objects, complex // path processing is done on a clone of the value. Freezable clone = ((Freezable)targetPropertyValue).Clone(); SetComplexPathClone( targetObject, targetProperty, targetPropertyValue, clone ); // Promote the clone to the EffectiveValues cache targetObject.InvalidateProperty(targetProperty); // We're supposed to have the animatable clone in place by now. But if // things went sour for whatever reason, halt the app instead of corrupting // the frozen object. if( targetObject.GetValue(targetProperty) != clone ) { throw new InvalidOperationException(SR.Get(SRID.Storyboard_ImmutableTargetNotSupported, path.Path)); } // Now that we have a clone, update the animatedObject and animatedProperty // with references to those on the clone. using(path.SetContext(targetObject)) { animatedObject = path.LastItem as DependencyObject; animatedProperty = path.LastAccessor as DependencyProperty; } // And set up to listen to changes on this clone. ChangeListener.ListenToChangesOnFreezable( targetObject, clone, targetProperty, (Freezable)targetPropertyValue ); } // Apply animation clock on the animated object/animated property. ObjectPropertyPair directApplyTarget = new ObjectPropertyPair( animatedObject, animatedProperty ); UpdateMappings( clockMappings, directApplyTarget, animationClock ); }
/// <summary> /// Begins the given Storyboard as a non-controllable Storyboard but /// with the given handoff policy. /// </summary> public void BeginStoryboard(Storyboard storyboard, HandoffBehavior handoffBehavior) { BeginStoryboard(storyboard, handoffBehavior, false); }
public static void ApplyAnimationClock(this IAnimatable animatable, DependencyProperty dependencyProperty, AnimationTimelineClock animationClock, HandoffBehavior handoffBehavior = HandoffBehavior.SnapshotAndReplace, object layerOwner = null) { IEnumerable <AnimationTimelineClock> animationClocks = animationClock != null ? new[] { animationClock } : new AnimationTimelineClock[0]; animatable.ApplyAnimationClocks(dependencyProperty, animationClocks, handoffBehavior, layerOwner); }
[FriendAccessAllowed] // Built into Core, also used by Framework. internal static void ApplyAnimationClocks( DependencyObject d, DependencyProperty dp, IList<AnimationClock> animationClocks, HandoffBehavior handoffBehavior) { Debug.Assert(animationClocks != null, "The animationClocks parameter should not be passed in as null."); Debug.Assert(animationClocks.Count > 0, "The animationClocks parameter should contain at least one clock."); Debug.Assert(!animationClocks.Contains(null), "The animationClocks parameter should not contain a null entry."); Debug.Assert(HandoffBehaviorEnum.IsDefined(handoffBehavior), "Public API caller of this internal method is responsible for validating that the HandoffBehavior value is valid." ); AnimationStorage storage = GetStorage(d, dp); // handoffBehavior is SnapshotAndReplace or the situation is such // that it is the equivalent because we have nothing to compose // with. if ( handoffBehavior == HandoffBehavior.SnapshotAndReplace || storage == null || storage._animationClocks == null) { if (storage != null) { EventHandler handler = new EventHandler(storage.OnCurrentStateInvalidated); // If we have a sticky snapshot value, the clock that would have // unstuck it is being replaced, so we need to remove our event // handler from that clock. if (storage._hasStickySnapshotValue) { storage._animationClocks[0].CurrentStateInvalidated -= handler; } // Calculate a snapshot value if we don't already have one // since the last tick. else { storage._snapshotValue = d.GetValue(dp); } // If we have a new clock in a stopped state, then the snapshot // value will be sticky. if (animationClocks[0].CurrentState == ClockState.Stopped) { storage._hasStickySnapshotValue = true; animationClocks[0].CurrentStateInvalidated += new EventHandler(storage.OnCurrentStateInvalidated); } // Otherwise it won't be sticky. else { storage._hasStickySnapshotValue = false; } storage.ClearAnimations(); } else { storage = CreateStorage(d, dp); } // Add and attach new animation. storage._animationClocks = new FrugalObjectList<AnimationClock>(animationClocks.Count); for (int i = 0; i < animationClocks.Count; i++) { Debug.Assert(animationClocks[i] != null); storage._animationClocks.Add(animationClocks[i]); storage.AttachAnimationClock(animationClocks[i], storage._removeRequestedHandler); } } else { Debug.Assert(handoffBehavior == HandoffBehavior.Compose); Debug.Assert(storage != null); Debug.Assert(storage._animationClocks != null); FrugalObjectList<AnimationClock> newClockCollection = new FrugalObjectList<AnimationClock>(storage._animationClocks.Count + animationClocks.Count); for (int i = 0; i < storage._animationClocks.Count; i++) { newClockCollection.Add(storage._animationClocks[i]); } storage._animationClocks = newClockCollection; for (int i = 0; i < animationClocks.Count; i++) { newClockCollection.Add(animationClocks[i]); storage.AttachAnimationClock(animationClocks[i], storage._removeRequestedHandler); } } storage.WritePostscript(); }
public static void ApplyAnimationClocks(this IAnimatable animatable, DependencyProperty dependencyProperty, IEnumerable <AnimationTimelineClock> animationClocks, HandoffBehavior handoffBehavior = HandoffBehavior.SnapshotAndReplace, object layerOwner = null) { if (handoffBehavior == HandoffBehavior.SnapshotAndReplace) { animatable.SetAnimationClocks(dependencyProperty, animationClocks, layerOwner); } else { animatable.AddAnimationClocks(dependencyProperty, animationClocks, layerOwner); } }
public static void BeginAnimation(this IAnimatable animatable, DependencyProperty dependencyProperty, AnimationTimeline animation, HandoffBehavior handoffBehavior = HandoffBehavior.SnapshotAndReplace, object layerOwner = null) { AnimationTimelineClock animationClock = (AnimationTimelineClock)animation.CreateClock(); animatable.ApplyAnimationClock(dependencyProperty, animationClock, handoffBehavior, layerOwner); animationClock.Begin(animatable.RootClock); }
public void Begin(FrameworkElement containingObject, HandoffBehavior handoffBehavior) { throw new NotImplementedException(); }
public void BeginStoryboard(Storyboard storyboard, HandoffBehavior handoffBehavior, bool isControllable) { if (storyboard == null) throw new ArgumentNullException("storyboard"); storyboard.Begin(this, handoffBehavior, isControllable); }
public void Begin(System.Windows.FrameworkContentElement containingObject, HandoffBehavior handoffBehavior) { }
public void BeginAnimation(System.Windows.DependencyProperty dp, AnimationTimeline animation, HandoffBehavior handoffBehavior) { }
public void Begin(System.Windows.FrameworkElement containingObject, HandoffBehavior handoffBehavior, bool isControllable) { }
/// <summary> /// Begins all animations underneath this storyboard, clock tree starts at the given containing object. /// </summary> public void Begin( FrameworkContentElement containingObject, HandoffBehavior handoffBehavior ) { Begin( containingObject, handoffBehavior, false ); }
public void BeginAnimation(DependencyProperty dp, AnimationTimeline animation, HandoffBehavior handoffBehavior);
/// <summary> /// Handles the handoff between conflicting animations. /// This method will, depending on the specified <paramref name="handoffBehavior"/>, stop conflicting /// animations (in case see cref="HandoffBehavior.SnapshotAndReplace"/>) /// or add them to the wait set for the given <paramref name="animationContext"/> /// (in case <see cref="HandoffBehavior.Compose"/>). /// The handoff behavior <see cref="HandoffBehavior.TemporaryReplace"/> will stop the conflicting /// animations, let the new animation run, and re-schedule the conflicting animations after the new animation. /// </summary> protected void ExecuteHandoff(AnimationContext animationContext, ICollection<AnimationContext> conflictingAnimations, HandoffBehavior handoffBehavior) { // Do the handoff depending on HandoffBehavior switch (handoffBehavior) { case HandoffBehavior.Compose: foreach (AnimationContext ac in conflictingAnimations) animationContext.WaitingFor.Add(ac); break; case HandoffBehavior.TemporaryReplace: foreach (AnimationContext ac in conflictingAnimations) ac.WaitingFor.Add(animationContext); break; case HandoffBehavior.SnapshotAndReplace: // Reset values of conflicting animations foreach (AnimationContext ac in conflictingAnimations) ResetAllValues(ac); // And remove those values which are handled by the new animation - // avoids flickering IDictionary<IDataDescriptor, object> animProperties = new Dictionary<IDataDescriptor, object>(); animationContext.Timeline.AddAllAnimatedProperties(animationContext.TimelineContext, animProperties); foreach (IDataDescriptor dd in animProperties.Keys) _valuesToSet.Remove(dd); break; default: throw new NotImplementedException("Animator.HandleConflicts: HandoffBehavior '" + handoffBehavior + "' is not implemented"); } }
/// <summary> /// Begins all animations underneath this storyboard, clock tree starts at the given containing object. /// </summary> public void Begin( FrameworkContentElement containingObject, HandoffBehavior handoffBehavior, bool isControllable ) { BeginCommon(containingObject, null, handoffBehavior, isControllable, Storyboard.Layers.Code ); }
internal void ApplyAnimationClocks( IList <AnimationClock> newAnimationClocks, HandoffBehavior handoffBehavior, object defaultDestinationValue) { Debug.Assert( newAnimationClocks == null || (newAnimationClocks.Count > 0 && !newAnimationClocks.Contains(null))); if (handoffBehavior == HandoffBehavior.SnapshotAndReplace) { Debug.Assert(defaultDestinationValue != DependencyProperty.UnsetValue, "We need a valid default destination value when peforming a snapshot and replace."); EventHandler handler = new EventHandler(OnCurrentStateInvalidated); // If we have a sticky snapshot value, the clock that would have // unstuck it is being replaced, so we need to remove our event // handler from that clock. if (_hasStickySnapshotValue) { _animationClocks[0].CurrentStateInvalidated -= handler; DetachAnimationClocks(); } // Otherwise if we have at least one clock take a new snapshot // value. else if (_animationClocks != null) { _snapshotValue = GetCurrentValue(defaultDestinationValue); DetachAnimationClocks(); } // Otherwise we can use the defaultDestinationValue as the // new snapshot value. else { _snapshotValue = defaultDestinationValue; } // If we have a new clock in a stopped state, then the snapshot // value will be sticky. if (newAnimationClocks != null && newAnimationClocks[0].CurrentState == ClockState.Stopped) { _hasStickySnapshotValue = true; newAnimationClocks[0].CurrentStateInvalidated += handler; } // Otherwise it won't be sticky. else { _hasStickySnapshotValue = false; } SetAnimationClocks(newAnimationClocks); } else { Debug.Assert(handoffBehavior == HandoffBehavior.Compose, "Unhandled handoffBehavior value."); Debug.Assert(defaultDestinationValue == DependencyProperty.UnsetValue, "We shouldn't take the time to calculate a default destination value when it isn't needed."); if (newAnimationClocks == null) { return; } else if (_animationClocks == null) { SetAnimationClocks(newAnimationClocks); } else { AppendAnimationClocks(newAnimationClocks); } } }
/// <summary> /// Begins all animations underneath this storyboard, clock tree starts at the given containing object. /// </summary> internal void BeginCommon( DependencyObject containingObject, INameScope nameScope, HandoffBehavior handoffBehavior, bool isControllable, Int64 layer) { if (containingObject == null) { throw new ArgumentNullException("containingObject"); } if (!HandoffBehaviorEnum.IsDefined(handoffBehavior)) { throw new ArgumentException(SR.Get(SRID.Storyboard_UnrecognizedHandoffBehavior)); } if (BeginTime == null) { // a null BeginTime means to not allocate or start the clock return; } // It's not possible to begin when there is no TimeManager. This condition // is known to occur during app shutdown. Since an app being shut down // won't care about its Storyboards, we silently exit. // If we don't exit here, we'll need to catch and handle the "no time // manager" exception implemented for bug #1247862 if( MediaContext.CurrentMediaContext.TimeManager == null ) { return; } if( TraceAnimation.IsEnabled ) { TraceAnimation.TraceActivityItem( TraceAnimation.StoryboardBegin, this, Name, containingObject, nameScope ); } // This table maps an [object,property] key pair to one or more clocks. // If we have knowledge of whether this Storyboard was changed between multiple // Begin(), we can cache this. But we don't know, so we don't cache. HybridDictionary simplePathClockMappings = new HybridDictionary(); // Create (and Begin) a clock tree corresponding to this Storyboard timeline tree Clock storyboardClockTree = CreateClock(isControllable); // We now have one or more clocks that are created from this storyboard. // However, the individual clocks are not necessarily intended for // the containing object so we need to do a tree walk and sort out // which clocks go on which objects and their properties. ClockTreeWalkRecursive( storyboardClockTree, containingObject, nameScope, null, /* target object */ null, /* target object name */ null, /* target property path */ handoffBehavior, simplePathClockMappings, layer); // Apply the storyboard's animation clocks we found in the tree walk ApplyAnimationClocks( simplePathClockMappings, handoffBehavior, layer ); if (isControllable) { // Save a reference to this clock tree on the containingObject. We // need it there in order to control this clock tree later. SetStoryboardClock(containingObject, storyboardClockTree); } return; }
/// <inheritdoc/> internal override void AddToCompositionChains(AnimationManager animationManager, HandoffBehavior handoffBehavior, AnimationInstance previousInstance) { var property = Property; if (property == null) { return; } // Get (or create) the animation composition chain. var compositionChain = animationManager.GetCompositionChain(property, Animation.Traits, true); if (handoffBehavior == HandoffBehavior.SnapshotAndReplace) { // Make a snapshot of the current animation value. compositionChain.TakeSnapshot(); } if (handoffBehavior == HandoffBehavior.Replace || handoffBehavior == HandoffBehavior.SnapshotAndReplace) { // Remove all previous animations. if (compositionChain.Count > 0) { var rootInstance = this.GetRoot(); for (int i = compositionChain.Count - 1; i >= 0; i--) { var animationInstance = compositionChain[i]; // Do not remove animation instances of the same animation tree! if (animationInstance.GetRoot() != rootInstance) { compositionChain.RemoveAt(i); } } } } AnimationInstance <T> referenceInstance = null; if (previousInstance != null) { // previousInstance is either a single animation instance or an animation tree that // should be replaced. Find the instance that is assigned to the current property. referenceInstance = previousInstance.GetAssignedInstance(Property) as AnimationInstance <T>; } if (referenceInstance == null) { // Add at the end of the animation composition chain. compositionChain.Add(this); } else { // Insert in animation composition chain at a certain index. int index = compositionChain.IndexOf(referenceInstance); if (index == -1) { // The referenceInstance has not been applied to the current property. compositionChain.Add(this); } else { // Insert after referenceInstance. index++; // Other animation instances of the same animation tree might have already been // inserted after referenceInstance. To maintain the correct order we need to add // this instance after the other instances of the same tree. var rootInstance = this.GetRoot(); var numberOfInstances = compositionChain.Count; while (index < numberOfInstances && compositionChain[index].GetRoot() == rootInstance) { index++; } compositionChain.Insert(index, this); } } }
/// <summary> /// Recursively walks the clock tree and determine the target object /// and property for each clock in the tree. /// </summary> /// <remarks> /// The currently active object and property path are passed in as parameters, /// they will be used unless a target/property specification exists on /// the Timeline object corresponding to the current clock. (So that the /// leaf-most reference wins.) /// /// The active object and property parameters may be null if they have /// never been specified. If we reach a leaf node clock and a needed attribute /// is still null, it is an error condition. Otherwise we keep hoping they'll be found. /// </remarks> private void ClockTreeWalkRecursive( Clock currentClock, /* No two calls will have the same currentClock */ DependencyObject containingObject, /* Remains the same through all the recursive calls */ INameScope nameScope, /* Remains the same through all the recursive calls */ DependencyObject parentObject, string parentObjectName, PropertyPath parentPropertyPath, HandoffBehavior handoffBehavior, /* Remains the same through all the recursive calls */ HybridDictionary clockMappings, Int64 layer /* Remains the same through all the recursive calls */) { Timeline currentTimeline = currentClock.Timeline; DependencyObject targetObject = parentObject; string currentObjectName = parentObjectName; PropertyPath currentPropertyPath = parentPropertyPath; // If we have target object/property information, use it instead of the // parent's information. string nameString = (string)currentTimeline.GetValue(TargetNameProperty); if( nameString != null ) { if( nameScope is Style ) { // We are inside a Style - we don't let people target anything. // They're only allowed to modify the Styled object, which is // already the implicit target. throw new InvalidOperationException(SR.Get(SRID.Storyboard_TargetNameNotAllowedInStyle, nameString)); } currentObjectName = nameString; } // The TargetProperty trumps the TargetName property. DependencyObject localTargetObject = (DependencyObject) currentTimeline.GetValue(TargetProperty); if( localTargetObject != null ) { targetObject = localTargetObject; currentObjectName = null; } PropertyPath propertyPath = (PropertyPath)currentTimeline.GetValue(TargetPropertyProperty); if( propertyPath != null ) { currentPropertyPath = propertyPath; } // Now see if the current clock is an animation clock if( currentClock is AnimationClock ) { DependencyProperty targetProperty = null; AnimationClock animationClock = (AnimationClock)currentClock; if( targetObject == null ) { // Resolve the target object name. If no name specified, use the // containing object. if( currentObjectName != null ) { DependencyObject mentor = Helper.FindMentor(containingObject); targetObject = ResolveTargetName(currentObjectName, nameScope, mentor); } else { // The containing object must be either an FE or FCE. // (Not a Storyboard, as used for "shared clocks" mode.) targetObject = containingObject as FrameworkElement; if(targetObject == null) { targetObject = containingObject as FrameworkContentElement; } if( targetObject == null ) { // The containing object is not an FE or FCE. throw new InvalidOperationException(SR.Get(SRID.Storyboard_NoTarget, currentTimeline.GetType().ToString() )); } } } // See if we have a property name to use. if( currentPropertyPath == null ) { throw new InvalidOperationException(SR.Get(SRID.Storyboard_TargetPropertyRequired, currentTimeline.GetType().ToString() )); } // A property name can be a straightforward property name (like "Angle") // but may be a more complex multi-step property path. The two cases // are handled differently. using(currentPropertyPath.SetContext(targetObject)) { if( currentPropertyPath.Length < 1 ) { throw new InvalidOperationException(SR.Get(SRID.Storyboard_PropertyPathEmpty)); } VerifyPathIsAnimatable(currentPropertyPath); if( currentPropertyPath.Length == 1 ) { // We have a simple single-step property. targetProperty = currentPropertyPath.GetAccessor(0) as DependencyProperty; if( targetProperty == null ) { // Unfortunately it's not a DependencyProperty. throw new InvalidOperationException(SR.Get(SRID.Storyboard_PropertyPathMustPointToDependencyProperty, currentPropertyPath.Path )); } VerifyAnimationIsValid(targetProperty, animationClock); ObjectPropertyPair animatedTarget = new ObjectPropertyPair(targetObject, targetProperty); UpdateMappings(clockMappings, animatedTarget, animationClock); } else // path.Length > 1 { // This is a multi-step property path that requires more extensive // setup. ProcessComplexPath(clockMappings, targetObject, currentPropertyPath, animationClock, handoffBehavior, layer); } } } else if ( currentClock is MediaClock ) // Not an animation clock - maybe a media clock? { // Yes it's a media clock. Try to find the corresponding object and // apply the clock to that object. ApplyMediaClock(nameScope, containingObject, targetObject, currentObjectName, (MediaClock) currentClock); } else { // None of the types we recognize as leaf node clock types - // recursively process child clocks. ClockGroup currentClockGroup = currentClock as ClockGroup; if (currentClockGroup != null) { ClockCollection childrenClocks = currentClockGroup.Children; for( int i = 0; i < childrenClocks.Count; i++ ) { ClockTreeWalkRecursive( childrenClocks[i], containingObject, nameScope, targetObject, currentObjectName, currentPropertyPath, handoffBehavior, clockMappings, layer); } } } }