Browse Source

Handle adding/removing application styles.

pull/3647/head
Steven Kirk 7 years ago
parent
commit
119a975610
  1. 16
      src/Avalonia.Controls/Application.cs
  2. 20
      src/Avalonia.Controls/TopLevel.cs
  3. 14
      src/Avalonia.Styling/Styling/IGlobalStyles.cs
  4. 39
      tests/Avalonia.Controls.UnitTests/TopLevelTests.cs

16
src/Avalonia.Controls/Application.cs

@ -46,6 +46,8 @@ namespace Avalonia
private Styles _styles; private Styles _styles;
private IResourceDictionary _resources; private IResourceDictionary _resources;
private bool _notifyingResourcesChanged; private bool _notifyingResourcesChanged;
private Action<IReadOnlyList<IStyle>> _stylesAdded;
private Action<IReadOnlyList<IStyle>> _stylesRemoved;
/// <summary> /// <summary>
/// Defines the <see cref="DataContext"/> property. /// Defines the <see cref="DataContext"/> property.
@ -202,6 +204,18 @@ namespace Avalonia
/// </summary> /// </summary>
public IApplicationLifetime ApplicationLifetime { get; set; } public IApplicationLifetime ApplicationLifetime { get; set; }
event Action<IReadOnlyList<IStyle>> IGlobalStyles.GlobalStylesAdded
{
add => _stylesAdded += value;
remove => _stylesAdded -= value;
}
event Action<IReadOnlyList<IStyle>> IGlobalStyles.GlobalStylesRemoved
{
add => _stylesRemoved += value;
remove => _stylesRemoved -= value;
}
/// <summary> /// <summary>
/// Initializes the application by loading XAML etc. /// Initializes the application by loading XAML etc.
/// </summary> /// </summary>
@ -217,10 +231,12 @@ namespace Avalonia
void IStyleHost.StylesAdded(IReadOnlyList<IStyle> styles) void IStyleHost.StylesAdded(IReadOnlyList<IStyle> styles)
{ {
_stylesAdded?.Invoke(styles);
} }
void IStyleHost.StylesRemoved(IReadOnlyList<IStyle> styles) void IStyleHost.StylesRemoved(IReadOnlyList<IStyle> styles)
{ {
_stylesRemoved?.Invoke(styles);
} }
/// <summary> /// <summary>

20
src/Avalonia.Controls/TopLevel.cs

@ -50,6 +50,7 @@ namespace Avalonia.Controls
private readonly IAccessKeyHandler _accessKeyHandler; private readonly IAccessKeyHandler _accessKeyHandler;
private readonly IKeyboardNavigationHandler _keyboardNavigationHandler; private readonly IKeyboardNavigationHandler _keyboardNavigationHandler;
private readonly IPlatformRenderInterface _renderInterface; private readonly IPlatformRenderInterface _renderInterface;
private readonly IGlobalStyles _globalStyles;
private Size _clientSize; private Size _clientSize;
private ILayoutManager _layoutManager; private ILayoutManager _layoutManager;
@ -94,6 +95,7 @@ namespace Avalonia.Controls
_inputManager = TryGetService<IInputManager>(dependencyResolver); _inputManager = TryGetService<IInputManager>(dependencyResolver);
_keyboardNavigationHandler = TryGetService<IKeyboardNavigationHandler>(dependencyResolver); _keyboardNavigationHandler = TryGetService<IKeyboardNavigationHandler>(dependencyResolver);
_renderInterface = TryGetService<IPlatformRenderInterface>(dependencyResolver); _renderInterface = TryGetService<IPlatformRenderInterface>(dependencyResolver);
_globalStyles = TryGetService<IGlobalStyles>(dependencyResolver);
Renderer = impl.CreateRenderer(this); Renderer = impl.CreateRenderer(this);
@ -112,6 +114,13 @@ namespace Avalonia.Controls
_keyboardNavigationHandler?.SetOwner(this); _keyboardNavigationHandler?.SetOwner(this);
_accessKeyHandler?.SetOwner(this); _accessKeyHandler?.SetOwner(this);
if (_globalStyles is object)
{
_globalStyles.GlobalStylesAdded += ((IStyleHost)this).StylesAdded;
_globalStyles.GlobalStylesRemoved += ((IStyleHost)this).StylesRemoved;
}
styler?.ApplyStyles(this); styler?.ApplyStyles(this);
ClientSize = impl.ClientSize; ClientSize = impl.ClientSize;
@ -215,10 +224,7 @@ namespace Avalonia.Controls
/// <inheritdoc/> /// <inheritdoc/>
double IRenderRoot.RenderScaling => PlatformImpl?.Scaling ?? 1; double IRenderRoot.RenderScaling => PlatformImpl?.Scaling ?? 1;
IStyleHost IStyleHost.StylingParent IStyleHost IStyleHost.StylingParent => _globalStyles;
{
get { return AvaloniaLocator.Current.GetService<IGlobalStyles>(); }
}
IRenderTarget IRenderRoot.CreateRenderTarget() => CreateRenderTarget(); IRenderTarget IRenderRoot.CreateRenderTarget() => CreateRenderTarget();
@ -267,6 +273,12 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
protected virtual void HandleClosed() protected virtual void HandleClosed()
{ {
if (_globalStyles is object)
{
_globalStyles.GlobalStylesAdded -= ((IStyleHost)this).StylesAdded;
_globalStyles.GlobalStylesRemoved -= ((IStyleHost)this).StylesRemoved;
}
var logicalArgs = new LogicalTreeAttachmentEventArgs(this, this, null); var logicalArgs = new LogicalTreeAttachmentEventArgs(this, this, null);
((ILogical)this).NotifyDetachedFromLogicalTree(logicalArgs); ((ILogical)this).NotifyDetachedFromLogicalTree(logicalArgs);

14
src/Avalonia.Styling/Styling/IGlobalStyles.cs

@ -1,6 +1,11 @@
// Copyright (c) The Avalonia Project. All rights reserved. // Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
#nullable enable
namespace Avalonia.Styling namespace Avalonia.Styling
{ {
/// <summary> /// <summary>
@ -8,5 +13,14 @@ namespace Avalonia.Styling
/// </summary> /// </summary>
public interface IGlobalStyles : IStyleHost public interface IGlobalStyles : IStyleHost
{ {
/// <summary>
/// Raised when styles are added to <see cref="Styles"/> or a nested styles collection.
/// </summary>
public event Action<IReadOnlyList<IStyle>> GlobalStylesAdded;
/// <summary>
/// Raised when styles are removed from <see cref="Styles"/> or a nested styles collection.
/// </summary>
public event Action<IReadOnlyList<IStyle>> GlobalStylesRemoved;
} }
} }

39
tests/Avalonia.Controls.UnitTests/TopLevelTests.cs

@ -9,6 +9,7 @@ using Avalonia.Input.Raw;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Styling;
using Avalonia.UnitTests; using Avalonia.UnitTests;
using Moq; using Moq;
using Xunit; using Xunit;
@ -269,6 +270,44 @@ namespace Avalonia.Controls.UnitTests
} }
} }
[Fact]
public void Reacts_To_Changes_In_Global_Styles()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var impl = new Mock<ITopLevelImpl>();
impl.SetupGet(x => x.Scaling).Returns(1);
var child = new Border { Classes = { "foo" } };
var target = new TestTopLevel(impl.Object)
{
Template = CreateTemplate(),
Content = child,
};
target.LayoutManager.ExecuteInitialLayoutPass(target);
Assert.Equal(new Thickness(0), child.BorderThickness);
var style = new Style(x => x.OfType<Border>().Class("foo"))
{
Setters =
{
new Setter(Border.BorderThicknessProperty, new Thickness(2))
}
};
Application.Current.Styles.Add(style);
target.LayoutManager.ExecuteInitialLayoutPass(target);
Assert.Equal(new Thickness(2), child.BorderThickness);
Application.Current.Styles.Remove(style);
Assert.Equal(new Thickness(0), child.BorderThickness);
}
}
private FuncControlTemplate<TestTopLevel> CreateTemplate() private FuncControlTemplate<TestTopLevel> CreateTemplate()
{ {
return new FuncControlTemplate<TestTopLevel>((x, scope) => return new FuncControlTemplate<TestTopLevel>((x, scope) =>

Loading…
Cancel
Save