diff --git a/src/Avalonia.Base/PropertyStore/FramePriority.cs b/src/Avalonia.Base/PropertyStore/FramePriority.cs
index 950a8375f2..f4f1ce447d 100644
--- a/src/Avalonia.Base/PropertyStore/FramePriority.cs
+++ b/src/Avalonia.Base/PropertyStore/FramePriority.cs
@@ -1,4 +1,5 @@
-using System.Diagnostics;
+using System;
+using System.Diagnostics;
using Avalonia.Data;
namespace Avalonia.PropertyStore
@@ -8,12 +9,15 @@ namespace Avalonia.PropertyStore
Animation,
AnimationTemplatedParentTheme,
AnimationTheme,
- StyleTrigger,
- StyleTriggerTemplatedParentTheme,
- StyleTriggerTheme,
+ TemplateStyleTrigger,
+ TemplateStyleTriggerTemplatedParentTheme,
+ TemplateStyleTriggerTheme,
Template,
TemplateTemplatedParentTheme,
TemplateTheme,
+ StyleTrigger,
+ StyleTriggerTemplatedParentTheme,
+ StyleTriggerTheme,
Style,
StyleTemplatedParentTheme,
StyleTheme,
@@ -21,11 +25,21 @@ namespace Avalonia.PropertyStore
internal static class FramePriorityExtensions
{
- public static FramePriority ToFramePriority(this BindingPriority priority, FrameType type = FrameType.Style)
+ public static FramePriority ToFramePriority(
+ this BindingPriority priority,
+ FrameType type = FrameType.Style,
+ bool isTemplateSelector = false)
{
- Debug.Assert(priority != BindingPriority.LocalValue);
- var p = (int)(priority > 0 ? priority : priority + 1);
- return (FramePriority)(p * 3 + (int)type);
+ var p = (priority, isTemplateSelector) switch
+ {
+ (BindingPriority.Animation, _) => FramePriority.Animation,
+ (BindingPriority.StyleTrigger, false) => FramePriority.StyleTrigger,
+ (BindingPriority.StyleTrigger, true) => FramePriority.TemplateStyleTrigger,
+ (BindingPriority.Template, _) => FramePriority.StyleTrigger,
+ (BindingPriority.Style, _) => FramePriority.Style,
+ _ => throw new ArgumentException("Invalid priority."),
+ };
+ return (FramePriority)((int)p + (int)type);
}
public static bool IsType(this FramePriority priority, FrameType type)
diff --git a/src/Avalonia.Base/PropertyStore/ValueFrame.cs b/src/Avalonia.Base/PropertyStore/ValueFrame.cs
index 7a9d1bb13a..498c614fe2 100644
--- a/src/Avalonia.Base/PropertyStore/ValueFrame.cs
+++ b/src/Avalonia.Base/PropertyStore/ValueFrame.cs
@@ -20,10 +20,10 @@ namespace Avalonia.PropertyStore
private ValueStore? _owner;
private bool _isShared;
- protected ValueFrame(BindingPriority priority, FrameType type)
+ protected ValueFrame(BindingPriority priority, FrameType type, bool isTemplateSelector = false)
{
Priority = priority;
- FramePriority = priority.ToFramePriority(type);
+ FramePriority = priority.ToFramePriority(type, isTemplateSelector);
}
public int EntryCount => _index.Count;
diff --git a/src/Avalonia.Base/PropertyStore/ValueStore.cs b/src/Avalonia.Base/PropertyStore/ValueStore.cs
index 2047f4d2d0..2a15dd3d24 100644
--- a/src/Avalonia.Base/PropertyStore/ValueStore.cs
+++ b/src/Avalonia.Base/PropertyStore/ValueStore.cs
@@ -772,7 +772,7 @@ namespace Avalonia.PropertyStore
Debug.Assert(oldValue != newValue);
Debug.Assert(oldValue is not null || newValue is not null);
- // If the value is set locally, propagaton ends here.
+ // If the value is set locally, propagation ends here.
if (_effectiveValues.ContainsKey(property) == true)
return;
@@ -825,7 +825,7 @@ namespace Avalonia.PropertyStore
if (current?.Priority < priority && current?.BasePriority < priority)
break;
- // Try to get an entry from the frame for the property we're reevaluating.
+ // Try to get an entry from the frame for the property we're re-evaluating.
var foundEntry = frame.TryGetEntryIfActive(property, out var entry, out var activeChanged);
// If the active state of the frame has changed since the last read, and
@@ -855,6 +855,9 @@ namespace Avalonia.PropertyStore
AddEffectiveValue(property, current);
current.SetAndRaise(this, entry, priority);
}
+
+ if (priority > BindingPriority.Animation)
+ break;
}
if (generation != _frameGeneration)
diff --git a/src/Avalonia.Base/Styling/ControlTheme.cs b/src/Avalonia.Base/Styling/ControlTheme.cs
index 75a3beb907..e9d802d22c 100644
--- a/src/Avalonia.Base/Styling/ControlTheme.cs
+++ b/src/Avalonia.Base/Styling/ControlTheme.cs
@@ -48,7 +48,7 @@ namespace Avalonia.Styling
if (HasSettersOrAnimations && TargetType.IsAssignableFrom(StyledElement.GetStyleKey(target)))
{
- Attach(target, null, type);
+ Attach(target, null, type, false);
return SelectorMatchResult.AlwaysThisType;
}
diff --git a/src/Avalonia.Base/Styling/Style.cs b/src/Avalonia.Base/Styling/Style.cs
index a5d89392e9..7b34feb8fd 100644
--- a/src/Avalonia.Base/Styling/Style.cs
+++ b/src/Avalonia.Base/Styling/Style.cs
@@ -74,7 +74,7 @@ namespace Avalonia.Styling
if (match.IsMatch)
{
- Attach(target, match.Activator, type);
+ Attach(target, match.Activator, type, Selector?.InTemplate ?? false);
}
result = match.Result;
diff --git a/src/Avalonia.Base/Styling/StyleBase.cs b/src/Avalonia.Base/Styling/StyleBase.cs
index 318e8d6890..907ebe1b4f 100644
--- a/src/Avalonia.Base/Styling/StyleBase.cs
+++ b/src/Avalonia.Base/Styling/StyleBase.cs
@@ -92,7 +92,7 @@ namespace Avalonia.Styling
return false;
}
- internal ValueFrame Attach(StyledElement target, IStyleActivator? activator, FrameType type)
+ internal ValueFrame Attach(StyledElement target, IStyleActivator? activator, FrameType type, bool isTemplateSelector)
{
if (target is not AvaloniaObject ao)
throw new InvalidOperationException("Styles can only be applied to AvaloniaObjects.");
@@ -107,7 +107,7 @@ namespace Avalonia.Styling
{
var canShareInstance = activator is null;
- instance = new StyleInstance(this, activator, type);
+ instance = new StyleInstance(this, activator, type, isTemplateSelector);
if (_setters is not null)
{
diff --git a/src/Avalonia.Base/Styling/StyleInstance.cs b/src/Avalonia.Base/Styling/StyleInstance.cs
index 61cb31c6d0..d6808e46a6 100644
--- a/src/Avalonia.Base/Styling/StyleInstance.cs
+++ b/src/Avalonia.Base/Styling/StyleInstance.cs
@@ -29,8 +29,9 @@ namespace Avalonia.Styling
public StyleInstance(
IStyle style,
IStyleActivator? activator,
- FrameType type)
- : base(GetPriority(activator), type)
+ FrameType type,
+ bool isTemplateSelector)
+ : base(GetPriority(activator), type, isTemplateSelector)
{
_activator = activator;
Source = style;
diff --git a/tests/Avalonia.Base.UnitTests/PropertyStore/ValueStoreTests_Frames.cs b/tests/Avalonia.Base.UnitTests/PropertyStore/ValueStoreTests_Frames.cs
index 3a307447ac..abc2bd398d 100644
--- a/tests/Avalonia.Base.UnitTests/PropertyStore/ValueStoreTests_Frames.cs
+++ b/tests/Avalonia.Base.UnitTests/PropertyStore/ValueStoreTests_Frames.cs
@@ -117,7 +117,7 @@ namespace Avalonia.Base.UnitTests.PropertyStore
private static StyleInstance InstanceStyle(Style style, StyledElement target)
{
- var result = new StyleInstance(style, null, FrameType.Style);
+ var result = new StyleInstance(style, null, FrameType.Style, false);
foreach (var setter in style.Setters)
result.Add(setter.Instance(result, target));
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlTemplateTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlTemplateTests.cs
index e21f6cd276..08c5c77e1c 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlTemplateTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlTemplateTests.cs
@@ -5,6 +5,7 @@ using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Diagnostics;
+using Avalonia.Layout;
using Avalonia.Markup.Xaml.Templates;
using Avalonia.Media;
using Avalonia.UnitTests;
@@ -246,6 +247,41 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
}
}
+ [Fact]
+ public void Foo()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+";
+ var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+ window.Show();
+
+ var control = (TemplatedControl)window.Content;
+ var button = Assert.IsType