Browse Source

Detach all styles when a style is removed from a control.

pull/1887/head
Jeremy Koritzinsky 8 years ago
parent
commit
ac11e7b3a8
  1. 2
      src/Avalonia.Styling/Styling/IStyle.cs
  2. 52
      src/Avalonia.Styling/Styling/Style.cs
  3. 8
      src/Avalonia.Styling/Styling/Styles.cs
  4. 9
      src/Avalonia.Styling/Styling/packages.config
  5. 10
      src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs
  6. 25
      tests/Avalonia.Styling.UnitTests/StyleTests.cs

2
src/Avalonia.Styling/Styling/IStyle.cs

@ -18,5 +18,7 @@ namespace Avalonia.Styling
/// The control that contains this style. May be null.
/// </param>
void Attach(IStyleable control, IStyleHost container);
void Detach();
}
}

52
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
/// </summary>
public class Style : AvaloniaObject, IStyle, ISetStyleParent
{
private static Dictionary<IStyleable, List<IDisposable>> _applied =
new Dictionary<IStyleable, List<IDisposable>>();
private static Dictionary<IStyleable, CompositeDisposable> _applied =
new Dictionary<IStyleable, CompositeDisposable>();
private IResourceNode _parent;
private CompositeDisposable _subscriptions;
private IResourceDictionary _resources;
private IList<IAnimation> _animations;
@ -88,6 +92,14 @@ namespace Avalonia.Styling
}
}
private CompositeDisposable Subscriptions
{
get
{
return _subscriptions ?? (_subscriptions = new CompositeDisposable(2));
}
}
/// <inheritdoc/>
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<IDisposable> GetSubscriptions(IStyleable control)
public void Detach()
{
List<IDisposable> 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<IDisposable>(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);
}

8
src/Avalonia.Styling/Styling/Styles.cs

@ -105,6 +105,14 @@ namespace Avalonia.Styling
}
}
public void Detach()
{
foreach (IStyle style in this)
{
style.Detach();
}
}
/// <inheritdoc/>
public bool TryGetResource(string key, out object value)
{

9
src/Avalonia.Styling/Styling/packages.config

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Rx-Core" version="2.2.5" targetFramework="portable-net45+win8" userInstalled="true" />
<package id="Rx-Interfaces" version="2.2.5" targetFramework="portable-net45+win8" userInstalled="true" />
<package id="Rx-Linq" version="2.2.5" targetFramework="portable-net45+win8" userInstalled="true" />
<package id="Rx-Main" version="2.2.5" targetFramework="portable-net45+win8" userInstalled="true" />
<package id="Rx-PlatformServices" version="2.2.5" targetFramework="portable-net45+win8" userInstalled="true" />
<package id="Splat" version="1.6.2" targetFramework="portable45-net45+win8" userInstalled="true" />
</packages>

10
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();
}
}
/// <inheritdoc/>
public bool TryGetResource(string key, out object value) => Loaded.TryGetResource(key, out value);
@ -90,4 +98,4 @@ namespace Avalonia.Markup.Xaml.Styling
_parent = parent;
}
}
}
}

25
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<Border>())
{
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<string> FooProperty =

Loading…
Cancel
Save