Browse Source

Dispose subscriptions on completed code-behind run of animation.

pull/1774/head
Jeremy Koritzinsky 8 years ago
parent
commit
7d1b7593a5
  1. 39
      src/Avalonia.Animation/Animation.cs

39
src/Avalonia.Animation/Animation.cs

@ -12,13 +12,14 @@ using System.Reflection;
using System.Linq;
using System.Threading.Tasks;
using System.Reactive.Linq;
using System.Reactive.Disposables;
namespace Avalonia.Animation
{
/// <summary>
/// Tracks the progress of an animation.
/// </summary>
public class Animation : AvaloniaList<KeyFrame>, IDisposable, IAnimation
public class Animation : AvaloniaList<KeyFrame>, IAnimation
{
private readonly static List<(Func<AvaloniaProperty, bool> Condition, Type Animator)> Animators = new List<(Func<AvaloniaProperty, bool>, Type)>
{
@ -43,7 +44,6 @@ namespace Avalonia.Animation
return null;
}
private List<IDisposable> _subscription = new List<IDisposable>();
public AvaloniaList<IAnimator> _animators { get; set; } = new AvaloniaList<IAnimator>();
/// <summary>
@ -76,10 +76,11 @@ namespace Avalonia.Animation
/// </summary>
public Easing Easing { get; set; } = new LinearEasing();
private IList<IAnimator> InterpretKeyframes(Animatable control)
private (IList<IAnimator> Animators, IList<IDisposable> subscriptions) InterpretKeyframes(Animatable control)
{
var handlerList = new List<(Type type, AvaloniaProperty property)>();
var animatorKeyFrames = new List<AnimatorKeyFrame>();
var subscriptions = new List<IDisposable>();
foreach (var keyframe in this)
{
@ -104,7 +105,7 @@ namespace Avalonia.Animation
var newKF = new AnimatorKeyFrame(handler, cue);
_subscription.Add(newKF.BindSetter(setter, control));
subscriptions.Add(newKF.BindSetter(setter, control));
animatorKeyFrames.Add(newKF);
}
@ -126,32 +127,21 @@ namespace Avalonia.Animation
animator.Add(keyframe);
}
return newAnimatorInstances;
}
/// <summary>
/// Cancels the animation.
/// </summary>
public void Dispose()
{
foreach (var sub in _subscription)
{
sub.Dispose();
}
return (newAnimatorInstances, subscriptions);
}
/// <inheritdocs/>
public IDisposable Apply(Animatable control, IObservable<bool> match, Action onComplete)
{
var animators = InterpretKeyframes(control);
var (animators, subscriptions) = InterpretKeyframes(control);
if (animators.Count == 1)
{
_subscription.Add(animators[0].Apply(this, control, match, onComplete));
subscriptions.Add(animators[0].Apply(this, control, match, onComplete));
}
else
{
var completionTasks = onComplete != null ? new List<Task>() : null;
foreach (IAnimator animator in InterpretKeyframes(control))
foreach (IAnimator animator in animators)
{
Action animatorOnComplete = null;
if (onComplete != null)
@ -160,7 +150,7 @@ namespace Avalonia.Animation
animatorOnComplete = () => tcs.SetResult(null);
completionTasks.Add(tcs.Task);
}
_subscription.Add(animator.Apply(this, control, match, animatorOnComplete));
subscriptions.Add(animator.Apply(this, control, match, animatorOnComplete));
}
if (onComplete != null)
@ -168,7 +158,7 @@ namespace Avalonia.Animation
Task.WhenAll(completionTasks).ContinueWith(_ => onComplete());
}
}
return this;
return new CompositeDisposable(subscriptions);
}
/// <inheritdocs/>
@ -179,7 +169,12 @@ namespace Avalonia.Animation
if (this.RepeatCount == RepeatCount.Loop)
run.SetException(new InvalidOperationException("Looping animations must not use the Run method."));
this.Apply(control, Observable.Return(true), () => run.SetResult(null));
IDisposable subscriptions = null;
subscriptions = this.Apply(control, Observable.Return(true), () =>
{
run.SetResult(null);
subscriptions.Dispose();
});
return run.Task;
}

Loading…
Cancel
Save