Browse Source

WIP: Hackfix for #9007

fixes/9007-priority-in-control-templates
Steven Kirk 2 years ago
parent
commit
b03ae24798
  1. 30
      src/Avalonia.Base/PropertyStore/FramePriority.cs
  2. 4
      src/Avalonia.Base/PropertyStore/ValueFrame.cs
  3. 7
      src/Avalonia.Base/PropertyStore/ValueStore.cs
  4. 2
      src/Avalonia.Base/Styling/ControlTheme.cs
  5. 2
      src/Avalonia.Base/Styling/Style.cs
  6. 4
      src/Avalonia.Base/Styling/StyleBase.cs
  7. 5
      src/Avalonia.Base/Styling/StyleInstance.cs
  8. 2
      tests/Avalonia.Base.UnitTests/PropertyStore/ValueStoreTests_Frames.cs
  9. 36
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlTemplateTests.cs

30
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)

4
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;

7
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)

2
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;
}

2
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;

4
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)
{

5
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;

2
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));

36
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 = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Window.Resources>
<ControlTheme x:Key='{x:Type Button}' TargetType='Button'>
<Style Selector='^:disabled'>
<Setter Property='Background' Value='LightGray'/>
</Style>
</ControlTheme>
</Window.Resources>
<TemplatedControl Background='LightBlue' IsEnabled='False'>
<TemplatedControl.Template>
<ControlTemplate TargetType='TemplatedControl'>
<Button Background='{TemplateBinding Background}'/>
</ControlTemplate>
</TemplatedControl.Template>
</TemplatedControl>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
window.Show();
var control = (TemplatedControl)window.Content;
var button = Assert.IsType<Button>(control.GetVisualChildren().Single());
var brush = Assert.IsAssignableFrom<ISolidColorBrush>(button.Background);
Assert.Equal(Colors.LightBlue, brush.Color);
}
}
[Fact]
public void ControlTemplate_With_Nested_Child_Is_Operational()
{

Loading…
Cancel
Save