private static void StopCurrentStoryboards(VisualStateGroup group, FrameworkElement element) { var currentStoryboards = group.GetCurrentStoryboards(); foreach (var sb in currentStoryboards) { if (sb != null) { sb.Remove(element); } } currentStoryboards.Clear(); }
public static void StartNewThenStopOld(this VisualStateGroup group, FrameworkElement element, params Storyboard[] newStoryboards) { // Start the new Storyboards for (int index = 0; index < newStoryboards.Length; ++index) { if (newStoryboards[index] == null) { continue; } newStoryboards[index].Begin(); //.Begin(element, HandoffBehavior.SnapshotAndReplace, true); // Silverlight had an issue where initially, a checked CheckBox would not show the check mark // until the second frame. They chose to do a Seek(0) at this point, which this line // is supposed to mimic. It does not seem to be equivalent, though, and WPF ends up // with some odd animation behavior. I haven't seen the CheckBox issue on WPF, so // commenting this out for now. // newStoryboards[index].SeekAlignedToLastTick(element, TimeSpan.Zero, TimeSeekOrigin.BeginTime); } var _currentStoryboards = group.GetCurrentStoryboards(); // Stop the old Storyboards for (int index = 0; index < _currentStoryboards.Count; ++index) { if (_currentStoryboards[index] == null) { continue; } _currentStoryboards[index].Stop(); // .Stop(element); } // Hold on to the running Storyboards _currentStoryboards.Clear(); for (int index = 0; index < newStoryboards.Length; ++index) { _currentStoryboards.Add(newStoryboards[index]); } }
/// <summary> /// Starts the specified <paramref name="newStoryboards"/> on the <paramref name="element"/>. /// Afterwards, the currently running storyboards of the visual state group are stopped. /// </summary> /// <param name="group">The group on which the storyboards will be started/stopped.</param> /// <param name="element">The element on which the storyboards will be run.</param> /// <param name="newStoryboards">The new storyboards to be run.</param> public static void StartNewAndStopOldStoryboards( this VisualStateGroup group, FrameworkElement element, params Storyboard[] newStoryboards) { if (group == null) { throw new ArgumentNullException(nameof(group)); } // Stop old storyboards before starting new ones. StopCurrentStoryboards(group, element); // Merge all of the passed Storyboards into one single master storyboard. // This fixes a bug in the WPF animation system which sometimes causes certain // storyboards to not fire a completed event. // See https://stackoverflow.com/questions/5002501/visualstatemanager-not-working-as-advertised // for details. Storyboard masterStoryboard = BuildMasterStoryboard(newStoryboards); if (masterStoryboard != null) { masterStoryboard.Begin(element, HandoffBehavior.SnapshotAndReplace, true); group.GetCurrentStoryboards().Add(masterStoryboard); } }
private static Storyboard GenerateDynamicTransitionAnimations(FrameworkElement root, VisualStateGroup group, VisualState newState, VisualTransition transition) { Storyboard dynamic = new Storyboard(); if (transition != null && transition.GeneratedDuration != null) { dynamic.Duration = transition.GeneratedDuration; } else { dynamic.Duration = new Duration(TimeSpan.Zero); } Dictionary <TimelineDataToken, Timeline> currentAnimations = FlattenTimelines(group.GetCurrentStoryboards()); Dictionary <TimelineDataToken, Timeline> transitionAnimations = FlattenTimelines(transition != null ? transition.Storyboard : null); Dictionary <TimelineDataToken, Timeline> newStateAnimations = FlattenTimelines(newState.Storyboard); // Remove any animations that the transition already animates. // There is no need to create an interstitial animation if one already exists. foreach (KeyValuePair <TimelineDataToken, Timeline> pair in transitionAnimations) { currentAnimations.Remove(pair.Key); newStateAnimations.Remove(pair.Key); } // Generate the "to" animations foreach (KeyValuePair <TimelineDataToken, Timeline> pair in newStateAnimations) { // The new "To" Animation -- the root is passed as a reference point for name // lookup. Timeline toAnimation = GenerateToAnimation(root, pair.Value, true); // If the animation is of a type that we can't generate transition animations // for, GenerateToAnimation will return null, and we should just keep going. if (toAnimation != null) { toAnimation.Duration = dynamic.Duration; dynamic.Children.Add(toAnimation); } // Remove this from the list of current state animations we have to consider next currentAnimations.Remove(pair.Key); } // Generate the "from" animations foreach (KeyValuePair <TimelineDataToken, Timeline> pair in currentAnimations) { Timeline fromAnimation = GenerateFromAnimation(pair.Value); if (fromAnimation != null) { fromAnimation.Duration = dynamic.Duration; string targetName = Storyboard.GetTargetName(pair.Value); Storyboard.SetTargetName(fromAnimation, targetName); // If the targetName of the existing Animation is known, then look up the // target DependencyObject target = String.IsNullOrEmpty(targetName) ? null : root.FindName(targetName) as DependencyObject; if (target != null) { Storyboard.SetTarget(fromAnimation, target); } string propertyName = Storyboard.GetTargetProperty(pair.Value); Storyboard.SetTargetProperty(fromAnimation, propertyName); dynamic.Children.Add(fromAnimation); } } return(dynamic); }