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 System;
using Avalonia.LogicalTree;
using Avalonia.LogicalTree;
namespace Avalonia.Styling.Activators
{
@ -14,7 +12,7 @@ namespace Avalonia.Styling.Activators
private readonly int _step;
private readonly int _offset;
private readonly bool _reversed;
private int _index = -1;
private int? _index;
public NthChildActivator(
ILogical control,
@ -30,7 +28,7 @@ namespace Avalonia.Styling.Activators
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;
}
@ -50,8 +48,7 @@ namespace Avalonia.Styling.Activators
// 1. Subscribed child index was changed
// 2. Child indexes were reset
// 3. We're a reversed (nth-last-child) selector and total count has changed
if ((e.Child == _control || e.Action == ChildIndexChangedAction.ChildIndexesReset) ||
(_reversed && e.Action == ChildIndexChangedAction.TotalCountChanged))
switch (e.Action)
{
// 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
@ -65,16 +62,17 @@ namespace Avalonia.Styling.Activators
// 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
// GetChildIndex may not return the correct index as the element isn't yet realized.
_index = e.Index;
ReevaluateIsActive();
_index = -1;
case ChildIndexChangedAction.ChildIndexChanged when e.Child == _control:
_index = e.Index;
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
{
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;
@ -63,7 +68,7 @@ namespace Avalonia.Styling.Activators
/// </returns>
protected bool ReevaluateIsActive()
{
var value = EvaluateIsActive();
var value = GetIsActive();
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.Templates;
using Avalonia.Data;
using Avalonia.PropertyStore;
using Avalonia.Media;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Moq;
@ -963,6 +963,72 @@ namespace Avalonia.Base.UnitTests.Styling
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
{
public static readonly StyledProperty<string> FooProperty =

Loading…
Cancel
Save