// Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; using System.Collections.Generic; using System.Linq; using System.Reactive.Linq; using Avalonia.Collections; using Avalonia.Data; using Avalonia.Animation.Animators; namespace Avalonia.Animation { /// /// Base class for all animatable objects. /// public class Animatable : AvaloniaObject { public static readonly StyledProperty ClockProperty = AvaloniaProperty.Register(nameof(Clock), inherits: true); public IClock Clock { get => GetValue(ClockProperty); set => SetValue(ClockProperty, value); } /// /// Defines the property. /// public static readonly DirectProperty TransitionsProperty = AvaloniaProperty.RegisterDirect( nameof(Transitions), o => o.Transitions, (o, v) => o.Transitions = v); private Transitions _transitions; private Dictionary _previousTransitions; /// /// Gets or sets the property transitions for the control. /// public Transitions Transitions { get { if (_transitions is null) _transitions = new Transitions(); if (_previousTransitions is null) _previousTransitions = new Dictionary(); return _transitions; } set { SetAndRaise(TransitionsProperty, ref _transitions, value); } } /// /// Reacts to a change in a value in /// order to animate the change if a is set for the property. /// /// The event args. protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e) { if (_transitions is null || _previousTransitions is null || e.Priority == BindingPriority.Animation) return; // PERF-SENSITIVE: Called on every property change. Don't use LINQ here (too many allocations). foreach (var transition in Transitions) { if (transition.Property == e.Property) { if (_previousTransitions.TryGetValue(e.Property, out var dispose)) dispose.Dispose(); var instance = transition.Apply(this, Clock ?? Avalonia.Animation.Clock.GlobalClock, e.OldValue, e.NewValue); _previousTransitions[e.Property] = instance; return; } } } } }