Browse Source

Handle adding/removing application styles.

pull/3647/head
Steven Kirk 6 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 IResourceDictionary _resources;
private bool _notifyingResourcesChanged;
private Action<IReadOnlyList<IStyle>> _stylesAdded;
private Action<IReadOnlyList<IStyle>> _stylesRemoved;
/// <summary>
/// Defines the <see cref="DataContext"/> property.
@ -202,6 +204,18 @@ namespace Avalonia
/// </summary>
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>
/// Initializes the application by loading XAML etc.
/// </summary>
@ -217,10 +231,12 @@ namespace Avalonia
void IStyleHost.StylesAdded(IReadOnlyList<IStyle> styles)
{
_stylesAdded?.Invoke(styles);
}
void IStyleHost.StylesRemoved(IReadOnlyList<IStyle> styles)
{
_stylesRemoved?.Invoke(styles);
}
/// <summary>

20
src/Avalonia.Controls/TopLevel.cs

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

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

@ -1,6 +1,11 @@
// 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.
using System;
using System.Collections.Generic;
#nullable enable
namespace Avalonia.Styling
{
/// <summary>
@ -8,5 +13,14 @@ namespace Avalonia.Styling
/// </summary>
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.LogicalTree;
using Avalonia.Platform;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Moq;
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()
{
return new FuncControlTemplate<TestTopLevel>((x, scope) =>

Loading…
Cancel
Save