Browse Source

Fixed style activator not publishing changes

Allows style animations to correctly stop.
Also fixed NthChildActivator when ChildIndexChanged and Index == -1.
pull/11815/head
Julien Lebosquain 3 years ago
parent
commit
c0e7dc8ecf
No known key found for this signature in database GPG Key ID: 1833CAD10ACC46FD
  1. 30
      src/Avalonia.Base/Styling/Activators/NthChildActivator.cs
  2. 11
      src/Avalonia.Base/Styling/Activators/StyleActivatorBase.cs
  3. 68
      tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs

30
src/Avalonia.Base/Styling/Activators/NthChildActivator.cs

@ -1,6 +1,4 @@
#nullable enable using Avalonia.LogicalTree;
using System;
using Avalonia.LogicalTree;
namespace Avalonia.Styling.Activators namespace Avalonia.Styling.Activators
{ {
@ -14,7 +12,7 @@ namespace Avalonia.Styling.Activators
private readonly int _step; private readonly int _step;
private readonly int _offset; private readonly int _offset;
private readonly bool _reversed; private readonly bool _reversed;
private int _index = -1; private int? _index;
public NthChildActivator( public NthChildActivator(
ILogical control, ILogical control,
@ -30,7 +28,7 @@ namespace Avalonia.Styling.Activators
protected override bool EvaluateIsActive() protected override bool EvaluateIsActive()
{ {
var index = _index >= 0 ? _index : _provider.GetChildIndex(_control); var index = _index ?? _provider.GetChildIndex(_control);
return NthChildSelector.Evaluate(index, _provider, _step, _offset, _reversed).IsMatch; return NthChildSelector.Evaluate(index, _provider, _step, _offset, _reversed).IsMatch;
} }
@ -50,8 +48,7 @@ namespace Avalonia.Styling.Activators
// 1. Subscribed child index was changed // 1. Subscribed child index was changed
// 2. Child indexes were reset // 2. Child indexes were reset
// 3. We're a reversed (nth-last-child) selector and total count has changed // 3. We're a reversed (nth-last-child) selector and total count has changed
if ((e.Child == _control || e.Action == ChildIndexChangedAction.ChildIndexesReset) || switch (e.Action)
(_reversed && e.Action == ChildIndexChangedAction.TotalCountChanged))
{ {
// We're using the _index field to pass the index of the child to EvaluateIsActive // We're using the _index field to pass the index of the child to EvaluateIsActive
// *only* when the active state is re-evaluated via this event handler. The docs // *only* when the active state is re-evaluated via this event handler. The docs
@ -65,16 +62,17 @@ namespace Avalonia.Styling.Activators
// IChildIndexProvider.GetChildIndex. This is because this event can be fired during // IChildIndexProvider.GetChildIndex. This is because this event can be fired during
// the process of realizing an element of a virtualized list; in this case calling // the process of realizing an element of a virtualized list; in this case calling
// GetChildIndex may not return the correct index as the element isn't yet realized. // GetChildIndex may not return the correct index as the element isn't yet realized.
_index = e.Index; case ChildIndexChangedAction.ChildIndexChanged when e.Child == _control:
ReevaluateIsActive(); _index = e.Index;
_index = -1; ReevaluateIsActive();
_index = null;
break;
case ChildIndexChangedAction.ChildIndexesReset:
case ChildIndexChangedAction.TotalCountChanged when _reversed:
_index = null;
ReevaluateIsActive();
break;
} }
} }
private void TotalCountChanged(object? sender, EventArgs e)
{
if (_reversed)
ReevaluateIsActive();
}
} }
} }

11
src/Avalonia.Base/Styling/Activators/StyleActivatorBase.cs

@ -6,9 +6,14 @@ namespace Avalonia.Styling.Activators
internal abstract class StyleActivatorBase : IStyleActivator internal abstract class StyleActivatorBase : IStyleActivator
{ {
private IStyleActivatorSink? _sink; private IStyleActivatorSink? _sink;
private bool _value; private bool? _value;
public bool GetIsActive() => _value = EvaluateIsActive(); public bool GetIsActive()
{
var value = EvaluateIsActive();
_value ??= value;
return value;
}
public bool IsSubscribed => _sink is not null; public bool IsSubscribed => _sink is not null;
@ -63,7 +68,7 @@ namespace Avalonia.Styling.Activators
/// </returns> /// </returns>
protected bool ReevaluateIsActive() protected bool ReevaluateIsActive()
{ {
var value = EvaluateIsActive(); var value = GetIsActive();
if (value != _value) if (value != _value)
{ {

68
tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs

@ -5,7 +5,7 @@ using Avalonia.Base.UnitTests.Animation;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.PropertyStore; using Avalonia.Media;
using Avalonia.Styling; using Avalonia.Styling;
using Avalonia.UnitTests; using Avalonia.UnitTests;
using Moq; using Moq;
@ -963,6 +963,72 @@ namespace Avalonia.Base.UnitTests.Styling
Assert.Equal(0.0, target.Double); Assert.Equal(0.0, target.Double);
} }
[Fact]
public void Animations_With_Activator_Trigger_Should_Be_Activated_And_Deactivated()
{
var clock = new TestClock();
var border = new Border();
var root = new TestRoot
{
Clock = clock,
Styles =
{
new Style(x => x.OfType<Border>().Not(default(Selector).Class("foo")))
{
Setters =
{
new Setter(Border.BackgroundProperty, Brushes.Yellow),
},
Animations =
{
new Avalonia.Animation.Animation
{
Duration = TimeSpan.FromSeconds(1.0),
Children =
{
new KeyFrame
{
Setters =
{
new Setter(Border.BackgroundProperty, Brushes.Green)
},
Cue = new Cue(0.0)
},
new KeyFrame
{
Setters =
{
new Setter(Border.BackgroundProperty, Brushes.Green)
},
Cue = new Cue(1.0)
}
}
}
}
},
new Style(x => x.OfType<Border>().Class("foo"))
{
Setters =
{
new Setter(Border.BackgroundProperty, Brushes.Blue),
}
}
},
Child = border
};
root.Measure(Size.Infinity);
Assert.Equal(Brushes.Yellow, border.Background);
clock.Step(TimeSpan.FromSeconds(0.5));
Assert.Equal(Brushes.Green, border.Background);
border.Classes.Add("foo");
Assert.Equal(Brushes.Blue, border.Background);
}
private class Class1 : Control private class Class1 : Control
{ {
public static readonly StyledProperty<string> FooProperty = public static readonly StyledProperty<string> FooProperty =

Loading…
Cancel
Save