private void HandleCompleted(bool stopped = false) { var completed = _storyboardCompleted && _compositionCompleted; if (!completed && !stopped) { return; } if (_storyboardCompleted && _compositionCompleted) { State = AnimationSetState.Completed; } else { State = AnimationSetState.Stopped; } if (_animationTCS != null && !_animationTCS.Task.IsCompleted) { Completed?.Invoke(this, new AnimationSetCompletedEventArgs() { Completed = _storyboardCompleted && _compositionCompleted }); _animationTCS.SetResult(State == AnimationSetState.Completed); } }
/// <summary> /// Initializes a new instance of the <see cref="AnimationSet"/> class. /// </summary> /// <param name="element">The associated element</param> public AnimationSet(UIElement element) { if (element == null) { throw new NullReferenceException("Element must not be null"); } var visual = ElementCompositionPreview.GetElementVisual(element); if (visual == null) { throw new NullReferenceException("Visual must not be null"); } Visual = visual; if (Visual.Compositor == null) { throw new NullReferenceException("Visual must have a compositor"); } Element = element; State = AnimationSetState.NotStarted; _compositor = Visual.Compositor; _compositionAnimations = new Dictionary <string, CompositionAnimation>(); _compositionEffectAnimations = new List <EffectAnimationDefinition>(); _directCompositionPropertyChanges = new Dictionary <string, object>(); _directCompositionEffectPropertyChanges = new List <EffectDirectPropertyChangeDefinition>(); _animationSets = new List <AnimationSet>(); _storyboard = new Storyboard(); _storyboardAnimations = new Dictionary <string, Timeline>(); _animationTasks = new List <AnimationTask>(); }
/// <summary> /// Starts all animations and returns an awaitable task. /// </summary> /// <returns>A <see cref="Task"/> that can be awaited until all animations have completed</returns> public async Task <bool> StartAsync() { if (_animationTCS == null || _animationTCS.Task.IsCompleted) { if (_animationTCS != null && _animationTCS.Task.IsCompleted) { foreach (var set in _animationSets) { set.State = AnimationSetState.NotStarted; set._animationTCS = null; } } State = AnimationSetState.Running; _animationTCS = new TaskCompletionSource <bool>(); } else { return(await _animationTCS.Task); } foreach (var set in _animationSets) { if (set.State != AnimationSetState.Completed) { var completed = await set.StartAsync(); if (!completed) { // the animation was stopped return(await _animationTCS.Task); } } } foreach (var task in _animationTasks) { if (task.Task != null && !task.Task.IsCompleted) { await task.Task; } // if _animationSet is stopped while task was running if (State == AnimationSetState.Stopped) { return(await _animationTCS.Task); } } _animationTasks.Clear(); foreach (var property in _directCompositionPropertyChanges) { typeof(Visual).GetProperty(property.Key).SetValue(Visual, property.Value); } foreach (var definition in _directCompositionEffectPropertyChanges) { definition.EffectBrush.Properties.InsertScalar(definition.PropertyName, definition.Value); } if (_compositionAnimations.Count > 0 || _compositionEffectAnimations.Count > 0) { if (_batch != null) { if (!_batch.IsEnded) { _batch.End(); } _batch.Completed -= Batch_Completed; } _batch = _compositor.CreateScopedBatch(CompositionBatchTypes.Animation); _batch.Completed += Batch_Completed; foreach (var anim in _compositionAnimations) { Visual.StartAnimation(anim.Key, anim.Value); } foreach (var effect in _compositionEffectAnimations) { effect.EffectBrush.StartAnimation(effect.PropertyName, effect.Animation); } _compositionCompleted = false; _batch.End(); } else { _compositionCompleted = true; } if (_storyboardAnimations.Count > 0) { _storyboardCompleted = false; _storyboard.Completed -= Storyboard_Completed; _storyboard.Completed += Storyboard_Completed; _storyboard.Begin(); } else { _storyboardCompleted = true; } HandleCompleted(); return(await _animationTCS.Task); }