diff --git a/src/Avalonia.Base/Animation/Transition.cs b/src/Avalonia.Base/Animation/Transition.cs index 519ed52578..2ad92c9183 100644 --- a/src/Avalonia.Base/Animation/Transition.cs +++ b/src/Avalonia.Base/Animation/Transition.cs @@ -1,53 +1,22 @@ using System; -using System.Diagnostics.CodeAnalysis; -using Avalonia.Animation.Easings; namespace Avalonia.Animation { /// /// Defines how a property should be animated using a transition. /// - public abstract class Transition : AvaloniaObject, ITransition + public abstract class Transition : TransitionBase { - private AvaloniaProperty? _prop; - - /// - /// Gets or sets the duration of the transition. - /// - public TimeSpan Duration { get; set; } - - /// - /// Gets or sets delay before starting the transition. - /// - public TimeSpan Delay { get; set; } = TimeSpan.Zero; - - /// - /// Gets the easing class to be used. - /// - public Easing Easing { get; set; } = new LinearEasing(); - - /// - [DisallowNull] - public AvaloniaProperty? Property + static Transition() { - get - { - return _prop; - } - set - { - if (!(value.PropertyType.IsAssignableFrom(typeof(T)))) - throw new InvalidCastException - ($"Invalid property type \"{typeof(T).Name}\" for this transition: {GetType().Name}."); - - _prop = value; - } + PropertyProperty.Changed.AddClassHandler>((x, e) => x.OnPropertyPropertyChanged(e)); } - AvaloniaProperty ITransition.Property + private void OnPropertyPropertyChanged(AvaloniaPropertyChangedEventArgs e) { - get => Property ?? throw new InvalidOperationException("Transition has no property specified."); - set => Property = value; + if ((e.NewValue is AvaloniaProperty newValue) && !newValue.PropertyType.IsAssignableFrom(typeof(T))) + throw new InvalidCastException + ($"Invalid property type \"{typeof(T).Name}\" for this transition: {GetType().Name}."); } /// @@ -55,11 +24,7 @@ namespace Avalonia.Animation /// internal abstract IObservable DoTransition(IObservable progress, T oldValue, T newValue); - /// - IDisposable ITransition.Apply(Animatable control, IClock clock, object? oldValue, object? newValue) - => Apply(control, clock, oldValue, newValue); - - internal virtual IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue) + internal override IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue) { if (Property is null) throw new InvalidOperationException("Transition has no property specified."); diff --git a/src/Avalonia.Base/Animation/TransitionBase.cs b/src/Avalonia.Base/Animation/TransitionBase.cs new file mode 100644 index 0000000000..8cc06ce7ed --- /dev/null +++ b/src/Avalonia.Base/Animation/TransitionBase.cs @@ -0,0 +1,100 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using Avalonia.Animation.Easings; + +namespace Avalonia.Animation +{ + /// + /// Defines how a property should be animated using a transition. + /// + public abstract class TransitionBase : AvaloniaObject, ITransition + { + /// + /// Defines the property. + /// + public static readonly DirectProperty DurationProperty = + AvaloniaProperty.RegisterDirect( + nameof(Duration), + o => o._duration, + (o, v) => o._duration = v); + + /// + /// Defines the property. + /// + public static readonly DirectProperty DelayProperty = + AvaloniaProperty.RegisterDirect( + nameof(Delay), + o => o._delay, + (o, v) => o._delay = v); + + /// + /// Defines the property. + /// + public static readonly DirectProperty EasingProperty = + AvaloniaProperty.RegisterDirect( + nameof(Easing), + o => o._easing, + (o, v) => o._easing = v); + + /// + /// Defines the property. + /// + public static readonly DirectProperty PropertyProperty = + AvaloniaProperty.RegisterDirect( + nameof(Property), + o => o._prop, + (o, v) => o._prop = v); + + private TimeSpan _duration; + private TimeSpan _delay = TimeSpan.Zero; + private Easing _easing = new LinearEasing(); + private AvaloniaProperty? _prop; + + /// + /// Gets or sets the duration of the transition. + /// + public TimeSpan Duration + { + get { return _duration; } + set { SetAndRaise(DurationProperty, ref _duration, value); } + } + + /// + /// Gets or sets delay before starting the transition. + /// + public TimeSpan Delay + { + get { return _delay; } + set { SetAndRaise(DelayProperty, ref _delay, value); } + } + + /// + /// Gets the easing class to be used. + /// + public Easing Easing + { + get { return _easing; } + set { SetAndRaise(EasingProperty, ref _easing, value); } + } + + /// + [DisallowNull] + public AvaloniaProperty? Property + { + get { return _prop; } + set { SetAndRaise(PropertyProperty, ref _prop, value); } + } + + AvaloniaProperty ITransition.Property + { + get => Property ?? throw new InvalidOperationException("Transition has no property specified."); + set => Property = value; + } + + /// + IDisposable ITransition.Apply(Animatable control, IClock clock, object? oldValue, object? newValue) + => Apply(control, clock, oldValue, newValue); + + internal abstract IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue); + } +}