From da28a6e4185f201c6f0fd44dfd2b55e574a34839 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 15 Dec 2023 19:15:56 +0100 Subject: [PATCH] Don't share style instances with Or selector. (#13969) * Added failing test for #13910. * Don't share style instances with Or selector. Fixes #13910. --- src/Avalonia.Base/Styling/ControlTheme.cs | 2 +- src/Avalonia.Base/Styling/Style.cs | 2 +- src/Avalonia.Base/Styling/StyleBase.cs | 10 +++-- .../Styling/StyleTests.cs | 39 +++++++++++++++++++ 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Base/Styling/ControlTheme.cs b/src/Avalonia.Base/Styling/ControlTheme.cs index 75a3beb907..6cd09e1808 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, true); return SelectorMatchResult.AlwaysThisType; } diff --git a/src/Avalonia.Base/Styling/Style.cs b/src/Avalonia.Base/Styling/Style.cs index a5d89392e9..44ffc22e91 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 is not OrSelector); } result = match.Result; diff --git a/src/Avalonia.Base/Styling/StyleBase.cs b/src/Avalonia.Base/Styling/StyleBase.cs index 318e8d6890..bc3457cb48 100644 --- a/src/Avalonia.Base/Styling/StyleBase.cs +++ b/src/Avalonia.Base/Styling/StyleBase.cs @@ -92,20 +92,24 @@ namespace Avalonia.Styling return false; } - internal ValueFrame Attach(StyledElement target, IStyleActivator? activator, FrameType type) + internal ValueFrame Attach( + StyledElement target, + IStyleActivator? activator, + FrameType type, + bool canShareInstance) { if (target is not AvaloniaObject ao) throw new InvalidOperationException("Styles can only be applied to AvaloniaObjects."); StyleInstance instance; - if (_sharedInstance is not null) + if (_sharedInstance is not null && canShareInstance) { instance = _sharedInstance; } else { - var canShareInstance = activator is null; + canShareInstance &= activator is null; instance = new StyleInstance(this, activator, type); diff --git a/tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs b/tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs index 52bee42d9d..b44078caeb 100644 --- a/tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs +++ b/tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs @@ -1029,6 +1029,28 @@ namespace Avalonia.Base.UnitTests.Styling Assert.Equal(Brushes.Blue, border.Background); } + [Fact] + public void Should_Not_Share_Instance_When_Or_Selector_Is_Present() + { + // Issue #13910 + Style style = new Style(x => Selectors.Or(x.OfType(), x.OfType().Class("bar"))) + { + Setters = + { + new Setter(Class1.FooProperty, "Foo"), + }, + }; + + var target1 = new Class1 { Classes = { "foo" } }; + var target2 = new Class2(); + + StyleHelpers.TryAttach(style, target1); + StyleHelpers.TryAttach(style, target2); + + Assert.Equal("Foo", target1.Foo); + Assert.Equal("foodefault", target2.Foo); + } + private class Class1 : Control { public static readonly StyledProperty FooProperty = @@ -1063,5 +1085,22 @@ namespace Avalonia.Base.UnitTests.Styling throw new NotImplementedException(); } } + + private class Class2 : Control + { + public static readonly StyledProperty FooProperty = + Class1.FooProperty.AddOwner(); + + public string Foo + { + get { return GetValue(FooProperty); } + set { SetValue(FooProperty, value); } + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + } + } } }