From ac11e7b3a8f7d0d5ed028ec9c8ce61c1b09976af Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Sun, 9 Sep 2018 16:44:31 -0500 Subject: [PATCH] Detach all styles when a style is removed from a control. --- src/Avalonia.Styling/Styling/IStyle.cs | 2 + src/Avalonia.Styling/Styling/Style.cs | 52 ++++++++++++++----- src/Avalonia.Styling/Styling/Styles.cs | 8 +++ src/Avalonia.Styling/Styling/packages.config | 9 ---- .../Styling/StyleInclude.cs | 10 +++- .../Avalonia.Styling.UnitTests/StyleTests.cs | 25 +++++++++ 6 files changed, 84 insertions(+), 22 deletions(-) delete mode 100644 src/Avalonia.Styling/Styling/packages.config diff --git a/src/Avalonia.Styling/Styling/IStyle.cs b/src/Avalonia.Styling/Styling/IStyle.cs index 5f12763825..3cf8491ae3 100644 --- a/src/Avalonia.Styling/Styling/IStyle.cs +++ b/src/Avalonia.Styling/Styling/IStyle.cs @@ -18,5 +18,7 @@ namespace Avalonia.Styling /// The control that contains this style. May be null. /// void Attach(IStyleable control, IStyleHost container); + + void Detach(); } } diff --git a/src/Avalonia.Styling/Styling/Style.cs b/src/Avalonia.Styling/Styling/Style.cs index 399be5470d..0d079e97da 100644 --- a/src/Avalonia.Styling/Styling/Style.cs +++ b/src/Avalonia.Styling/Styling/Style.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Reactive.Disposables; using System.Reactive.Linq; using Avalonia.Animation; using Avalonia.Controls; @@ -15,9 +16,12 @@ namespace Avalonia.Styling /// public class Style : AvaloniaObject, IStyle, ISetStyleParent { - private static Dictionary> _applied = - new Dictionary>(); + private static Dictionary _applied = + new Dictionary(); private IResourceNode _parent; + + private CompositeDisposable _subscriptions; + private IResourceDictionary _resources; private IList _animations; @@ -88,6 +92,14 @@ namespace Avalonia.Styling } } + private CompositeDisposable Subscriptions + { + get + { + return _subscriptions ?? (_subscriptions = new CompositeDisposable(2)); + } + } + /// IResourceNode IResourceNode.ResourceParent => _parent; @@ -109,7 +121,9 @@ namespace Avalonia.Styling if (match.ImmediateResult != false) { - var subs = GetSubscriptions(control); + var controlSubscriptions = GetSubscriptions(control); + + var subs = new CompositeDisposable(Setters.Count + Animations.Count); foreach (var animation in Animations) { @@ -129,17 +143,25 @@ namespace Avalonia.Styling var sub = setter.Apply(this, control, match.ObservableResult); subs.Add(sub); } + + controlSubscriptions.Add(subs); + Subscriptions.Add(subs); } } else if (control == container) { - var subs = GetSubscriptions(control); + var controlSubscriptions = GetSubscriptions(control); + + var subs = new CompositeDisposable(Setters.Count); foreach (var setter in Setters) { var sub = setter.Apply(this, control, null); subs.Add(sub); } + + controlSubscriptions.Add(subs); + Subscriptions.Add(subs); } } @@ -180,16 +202,25 @@ namespace Avalonia.Styling throw new InvalidOperationException("The Style already has a parent."); } + if (parent == null) + { + Detach(); + } + _parent = parent; } - private static List GetSubscriptions(IStyleable control) + public void Detach() { - List subscriptions; + _subscriptions?.Dispose(); + _subscriptions = null; + } - if (!_applied.TryGetValue(control, out subscriptions)) + private static CompositeDisposable GetSubscriptions(IStyleable control) + { + if (!_applied.TryGetValue(control, out var subscriptions)) { - subscriptions = new List(2); + subscriptions = new CompositeDisposable(2); subscriptions.Add(control.StyleDetach.Subscribe(ControlDetach)); _applied.Add(control, subscriptions); } @@ -206,10 +237,7 @@ namespace Avalonia.Styling { var subscriptions = _applied[control]; - foreach (var subscription in subscriptions) - { - subscription.Dispose(); - } + subscriptions.Dispose(); _applied.Remove(control); } diff --git a/src/Avalonia.Styling/Styling/Styles.cs b/src/Avalonia.Styling/Styling/Styles.cs index 714e7f6def..22ed8bb241 100644 --- a/src/Avalonia.Styling/Styling/Styles.cs +++ b/src/Avalonia.Styling/Styling/Styles.cs @@ -105,6 +105,14 @@ namespace Avalonia.Styling } } + public void Detach() + { + foreach (IStyle style in this) + { + style.Detach(); + } + } + /// public bool TryGetResource(string key, out object value) { diff --git a/src/Avalonia.Styling/Styling/packages.config b/src/Avalonia.Styling/Styling/packages.config deleted file mode 100644 index aa2dbd982f..0000000000 --- a/src/Avalonia.Styling/Styling/packages.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs b/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs index 3580b4fcb5..fc2656f236 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs @@ -70,6 +70,14 @@ namespace Avalonia.Markup.Xaml.Styling } } + public void Detach() + { + if (Source != null) + { + Loaded.Detach(); + } + } + /// public bool TryGetResource(string key, out object value) => Loaded.TryGetResource(key, out value); @@ -90,4 +98,4 @@ namespace Avalonia.Markup.Xaml.Styling _parent = parent; } } -} \ No newline at end of file +} diff --git a/tests/Avalonia.Styling.UnitTests/StyleTests.cs b/tests/Avalonia.Styling.UnitTests/StyleTests.cs index 5ef559b887..53e0ae5db7 100644 --- a/tests/Avalonia.Styling.UnitTests/StyleTests.cs +++ b/tests/Avalonia.Styling.UnitTests/StyleTests.cs @@ -167,6 +167,31 @@ namespace Avalonia.Styling.UnitTests Assert.Equal(new Thickness(0), border.BorderThickness); } + [Fact] + public void Style_Should_Detach_Setters_When_Detach_Is_Called() + { + Border border; + + var style = new Style(x => x.OfType()) + { + Setters = new[] + { + new Setter(Border.BorderThicknessProperty, new Thickness(4)), + } + }; + + var root = new TestRoot + { + Child = border = new Border(), + }; + + style.Attach(border, null); + + Assert.Equal(new Thickness(4), border.BorderThickness); + style.Detach(); + Assert.Equal(new Thickness(0), border.BorderThickness); + } + private class Class1 : Control { public static readonly StyledProperty FooProperty =