Browse Source

Merge branch 'master' into fixes/newTextProcessingIssues

pull/10408/head
Benedikt Stebner 3 years ago
committed by GitHub
parent
commit
de13de2201
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 39
      src/Avalonia.Base/Controls/ResourceNodeExtensions.cs
  2. 46
      src/Avalonia.Base/StyledElement.cs
  3. 22
      src/Avalonia.Base/Styling/IGlobalThemeVariantProvider.cs
  4. 26
      src/Avalonia.Base/Styling/IThemeVariantHost.cs
  5. 17
      src/Avalonia.Base/Styling/ThemeVariant.cs
  6. 71
      src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
  7. 19
      src/Avalonia.Controls/Application.cs
  8. 2
      src/Avalonia.Controls/Control.cs
  9. 9
      src/Avalonia.Controls/Primitives/Popup.cs
  10. 8
      src/Avalonia.Controls/ThemeVariantScope.cs
  11. 14
      src/Avalonia.Controls/TopLevel.cs
  12. 2
      src/Avalonia.Diagnostics/Diagnostics/Controls/Application.cs
  13. 104
      src/Avalonia.Themes.Simple/Controls/SplitButton.xaml
  14. 6
      src/Avalonia.Themes.Simple/Controls/SplitView.xaml
  15. 91
      src/Avalonia.Themes.Simple/Controls/ToggleSwitch.xaml
  16. 2
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs
  17. 77
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ThemeDictionariesTests.cs

39
src/Avalonia.Base/Controls/ResourceNodeExtensions.cs

@ -138,18 +138,18 @@ namespace Avalonia.Controls
protected override void Initialize() protected override void Initialize()
{ {
_target.ResourcesChanged += ResourcesChanged; _target.ResourcesChanged += ResourcesChanged;
if (_target is StyledElement themeStyleable) if (_target is IThemeVariantHost themeVariantHost)
{ {
themeStyleable.PropertyChanged += PropertyChanged; themeVariantHost.ActualThemeVariantChanged += ActualThemeVariantChanged;
} }
} }
protected override void Deinitialize() protected override void Deinitialize()
{ {
_target.ResourcesChanged -= ResourcesChanged; _target.ResourcesChanged -= ResourcesChanged;
if (_target is StyledElement themeStyleable) if (_target is IThemeVariantHost themeVariantHost)
{ {
themeStyleable.PropertyChanged -= PropertyChanged; themeVariantHost.ActualThemeVariantChanged -= ActualThemeVariantChanged;
} }
} }
@ -163,18 +163,15 @@ namespace Avalonia.Controls
PublishNext(GetValue()); PublishNext(GetValue());
} }
private void PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) private void ActualThemeVariantChanged(object? sender, EventArgs e)
{ {
if (e.Property == StyledElement.ActualThemeVariantProperty) PublishNext(GetValue());
{
PublishNext(GetValue());
}
} }
private object? GetValue() private object? GetValue()
{ {
if (_target is not StyledElement themeStyleable if (_target is not IThemeVariantHost themeVariantHost
|| !_target.TryFindResource(_key, themeStyleable.ActualThemeVariant, out var value)) || !_target.TryFindResource(_key, themeVariantHost.ActualThemeVariant, out var value))
{ {
value = _target.FindResource(_key) ?? AvaloniaProperty.UnsetValue; value = _target.FindResource(_key) ?? AvaloniaProperty.UnsetValue;
} }
@ -236,9 +233,9 @@ namespace Avalonia.Controls
{ {
_owner.ResourcesChanged -= ResourcesChanged; _owner.ResourcesChanged -= ResourcesChanged;
} }
if (_owner is StyledElement styleable) if (_owner is IThemeVariantHost themeVariantHost)
{ {
styleable.PropertyChanged += PropertyChanged; themeVariantHost.ActualThemeVariantChanged += ActualThemeVariantChanged;
} }
_owner = _target.Owner; _owner = _target.Owner;
@ -247,20 +244,18 @@ namespace Avalonia.Controls
{ {
_owner.ResourcesChanged += ResourcesChanged; _owner.ResourcesChanged += ResourcesChanged;
} }
if (_owner is StyledElement styleable2) if (_owner is IThemeVariantHost themeVariantHost2)
{ {
styleable2.PropertyChanged += PropertyChanged; themeVariantHost2.ActualThemeVariantChanged -= ActualThemeVariantChanged;
} }
PublishNext(); PublishNext();
} }
private void PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) private void ActualThemeVariantChanged(object? sender, EventArgs e)
{ {
if (e.Property == StyledElement.ActualThemeVariantProperty) PublishNext();
{
PublishNext();
}
} }
private void ResourcesChanged(object? sender, ResourcesChangedEventArgs e) private void ResourcesChanged(object? sender, ResourcesChangedEventArgs e)
@ -270,8 +265,8 @@ namespace Avalonia.Controls
private object? GetValue() private object? GetValue()
{ {
if (!(_target.Owner is StyledElement themeStyleable) if (!(_target.Owner is IThemeVariantHost themeVariantHost)
|| !_target.Owner.TryFindResource(_key, themeStyleable.ActualThemeVariant, out var value)) || !_target.Owner.TryFindResource(_key, themeVariantHost.ActualThemeVariant, out var value))
{ {
value = _target.Owner?.FindResource(_key) ?? AvaloniaProperty.UnsetValue; value = _target.Owner?.FindResource(_key) ?? AvaloniaProperty.UnsetValue;
} }

46
src/Avalonia.Base/StyledElement.cs

@ -28,7 +28,7 @@ namespace Avalonia
public class StyledElement : Animatable, public class StyledElement : Animatable,
IDataContextProvider, IDataContextProvider,
ILogical, ILogical,
IResourceHost, IThemeVariantHost,
IStyleHost, IStyleHost,
IStyleable, IStyleable,
ISetLogicalParent, ISetLogicalParent,
@ -75,23 +75,6 @@ namespace Avalonia
public static readonly StyledProperty<ControlTheme?> ThemeProperty = public static readonly StyledProperty<ControlTheme?> ThemeProperty =
AvaloniaProperty.Register<StyledElement, ControlTheme?>(nameof(Theme)); AvaloniaProperty.Register<StyledElement, ControlTheme?>(nameof(Theme));
/// <summary>
/// Defines the <see cref="ActualThemeVariant"/> property.
/// </summary>
public static readonly StyledProperty<ThemeVariant> ActualThemeVariantProperty =
AvaloniaProperty.Register<StyledElement, ThemeVariant>(
nameof(ThemeVariant),
inherits: true,
defaultValue: ThemeVariant.Light);
/// <summary>
/// Defines the RequestedThemeVariant property.
/// </summary>
public static readonly StyledProperty<ThemeVariant?> RequestedThemeVariantProperty =
AvaloniaProperty.Register<StyledElement, ThemeVariant?>(
nameof(ThemeVariant),
defaultValue: ThemeVariant.Default);
private static readonly ControlTheme s_invalidTheme = new ControlTheme(); private static readonly ControlTheme s_invalidTheme = new ControlTheme();
private int _initCount; private int _initCount;
private string? _name; private string? _name;
@ -160,6 +143,9 @@ namespace Avalonia
/// </summary> /// </summary>
public event EventHandler<ResourcesChangedEventArgs>? ResourcesChanged; public event EventHandler<ResourcesChangedEventArgs>? ResourcesChanged;
/// <inheritdoc />
public event EventHandler? ActualThemeVariantChanged;
/// <summary> /// <summary>
/// Gets or sets the name of the styled element. /// Gets or sets the name of the styled element.
/// </summary> /// </summary>
@ -278,15 +264,6 @@ namespace Avalonia
set => SetValue(ThemeProperty, value); set => SetValue(ThemeProperty, value);
} }
/// <summary>
/// Gets the UI theme that is currently used by the element, which might be different than the <see cref="RequestedThemeVariantProperty"/>.
/// </summary>
/// <returns>
/// If current control is contained in the ThemeVariantScope, TopLevel or Application with non-default RequestedThemeVariant, that value will be returned.
/// Otherwise, current OS theme variant is returned.
/// </returns>
public ThemeVariant ActualThemeVariant => GetValue(ActualThemeVariantProperty);
/// <summary> /// <summary>
/// Gets the styled element's logical children. /// Gets the styled element's logical children.
/// </summary> /// </summary>
@ -325,6 +302,9 @@ namespace Avalonia
/// </summary> /// </summary>
public StyledElement? Parent { get; private set; } public StyledElement? Parent { get; private set; }
/// <inheritdoc />
public ThemeVariant ActualThemeVariant => GetValue(ThemeVariant.ActualThemeVariantProperty);
/// <summary> /// <summary>
/// Gets the styled element's logical parent. /// Gets the styled element's logical parent.
/// </summary> /// </summary>
@ -644,13 +624,19 @@ namespace Avalonia
base.OnPropertyChanged(change); base.OnPropertyChanged(change);
if (change.Property == ThemeProperty) if (change.Property == ThemeProperty)
{
OnControlThemeChanged(); OnControlThemeChanged();
else if (change.Property == RequestedThemeVariantProperty) }
else if (change.Property == ThemeVariant.RequestedThemeVariantProperty)
{ {
if (change.GetNewValue<ThemeVariant>() is {} themeVariant && themeVariant != ThemeVariant.Default) if (change.GetNewValue<ThemeVariant>() is {} themeVariant && themeVariant != ThemeVariant.Default)
SetValue(ActualThemeVariantProperty, themeVariant); SetValue(ThemeVariant.ActualThemeVariantProperty, themeVariant);
else else
ClearValue(ActualThemeVariantProperty); ClearValue(ThemeVariant.ActualThemeVariantProperty);
}
else if (change.Property == ThemeVariant.ActualThemeVariantProperty)
{
ActualThemeVariantChanged?.Invoke(this, EventArgs.Empty);
} }
} }

22
src/Avalonia.Base/Styling/IGlobalThemeVariantProvider.cs

@ -1,22 +0,0 @@
using System;
using Avalonia.Controls;
using Avalonia.Metadata;
namespace Avalonia.Styling;
/// <summary>
/// Interface for an application host element with a root theme variant.
/// </summary>
[Unstable]
public interface IGlobalThemeVariantProvider : IResourceHost
{
/// <summary>
/// Gets the UI theme variant that is used by the control (and its child elements) for resource determination.
/// </summary>
ThemeVariant ActualThemeVariant { get; }
/// <summary>
/// Raised when the theme variant is changed on the element or an ancestor of the element.
/// </summary>
event EventHandler? ActualThemeVariantChanged;
}

26
src/Avalonia.Base/Styling/IThemeVariantHost.cs

@ -0,0 +1,26 @@
using System;
using Avalonia.Controls;
using Avalonia.Metadata;
namespace Avalonia.Styling;
/// <summary>
/// Interface for the host element with a theme variant.
/// </summary>
[Unstable]
public interface IThemeVariantHost : IResourceHost
{
/// <summary>
/// Gets the UI theme that is currently used by the element, which might be different than the RequestedThemeVariantProperty.
/// </summary>
/// <returns>
/// If current control is contained in the ThemeVariantScope, TopLevel or Application with non-default RequestedThemeVariant, that value will be returned.
/// Otherwise, current OS theme variant is returned.
/// </returns>
ThemeVariant ActualThemeVariant { get; }
/// <summary>
/// Raised when the theme variant is changed on the element or an ancestor of the element.
/// </summary>
event EventHandler? ActualThemeVariantChanged;
}

17
src/Avalonia.Base/Styling/ThemeVariant.cs

@ -6,11 +6,26 @@ using Avalonia.Platform;
namespace Avalonia.Styling; namespace Avalonia.Styling;
/// <summary> /// <summary>
/// Specifies a UI theme variant that should be used for the /// Specifies a UI theme variant that should be used for the Control and Application types.
/// </summary> /// </summary>
[TypeConverter(typeof(ThemeVariantTypeConverter))] [TypeConverter(typeof(ThemeVariantTypeConverter))]
public sealed record ThemeVariant public sealed record ThemeVariant
{ {
/// <summary>
/// Defines the ActualThemeVariant property.
/// </summary>
internal static readonly StyledProperty<ThemeVariant> ActualThemeVariantProperty =
AvaloniaProperty.Register<StyledElement, ThemeVariant>(
"ActualThemeVariant",
inherits: true);
/// <summary>
/// Defines the RequestedThemeVariant property.
/// </summary>
internal static readonly StyledProperty<ThemeVariant?> RequestedThemeVariantProperty =
AvaloniaProperty.Register<StyledElement, ThemeVariant?>(
"RequestedThemeVariant", defaultValue: Default);
/// <summary> /// <summary>
/// Creates a new instance of the <see cref="ThemeVariant"/> /// Creates a new instance of the <see cref="ThemeVariant"/>
/// </summary> /// </summary>

71
src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml

@ -1,6 +1,48 @@
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" <Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:collections="using:Avalonia.Collections"> xmlns:collections="using:Avalonia.Collections">
<Styles.Resources> <Styles.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="DataGridColumnHeaderForegroundBrush" Color="{DynamicResource SystemBaseMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderBackgroundBrush" Color="{DynamicResource SystemAltHighColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderPressedBackgroundBrush" Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderDraggedBackgroundBrush" Color="{DynamicResource SystemChromeMediumLowColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderBackgroundBrush" Color="{DynamicResource SystemChromeMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderPressedBackgroundBrush" Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderForegroundBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridRowHoveredBackgroundColor" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridRowInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="DataGridCellFocusVisualPrimaryBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridCellFocusVisualSecondaryBrush" Color="{DynamicResource SystemAltMediumColor}" />
<SolidColorBrush x:Key="DataGridCellInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="DataGridGridLinesBrush" Opacity="0.4" Color="{DynamicResource SystemBaseMediumLowColor}" />
<SolidColorBrush x:Key="DataGridDetailsPresenterBackgroundBrush" Color="{DynamicResource SystemChromeMediumLowColor}" />
</ResourceDictionary>
<ResourceDictionary x:Key="Default">
<SolidColorBrush x:Key="DataGridColumnHeaderForegroundBrush" Color="{DynamicResource SystemBaseMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderBackgroundBrush" Color="{DynamicResource SystemAltHighColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderPressedBackgroundBrush" Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderDraggedBackgroundBrush" Color="{DynamicResource SystemChromeMediumLowColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderBackgroundBrush" Color="{DynamicResource SystemChromeMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderPressedBackgroundBrush" Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderForegroundBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridRowHoveredBackgroundColor" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridRowInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="DataGridCellFocusVisualPrimaryBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridCellFocusVisualSecondaryBrush" Color="{DynamicResource SystemAltMediumColor}" />
<SolidColorBrush x:Key="DataGridCellInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="DataGridGridLinesBrush" Opacity="0.4" Color="{DynamicResource SystemBaseMediumLowColor}" />
<SolidColorBrush x:Key="DataGridDetailsPresenterBackgroundBrush" Color="{DynamicResource SystemChromeMediumLowColor}" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<x:Double x:Key="ListAccentLowOpacity">0.6</x:Double> <x:Double x:Key="ListAccentLowOpacity">0.6</x:Double>
<x:Double x:Key="ListAccentMediumOpacity">0.8</x:Double> <x:Double x:Key="ListAccentMediumOpacity">0.8</x:Double>
@ -9,19 +51,6 @@
<StreamGeometry x:Key="DataGridRowGroupHeaderIconClosedPath">M515 93l930 931l-930 931l90 90l1022 -1021l-1022 -1021z</StreamGeometry> <StreamGeometry x:Key="DataGridRowGroupHeaderIconClosedPath">M515 93l930 931l-930 931l90 90l1022 -1021l-1022 -1021z</StreamGeometry>
<StreamGeometry x:Key="DataGridRowGroupHeaderIconOpenedPath">M109 486 19 576 1024 1581 2029 576 1939 486 1024 1401z</StreamGeometry> <StreamGeometry x:Key="DataGridRowGroupHeaderIconOpenedPath">M109 486 19 576 1024 1581 2029 576 1939 486 1024 1401z</StreamGeometry>
<SolidColorBrush x:Key="DataGridColumnHeaderForegroundBrush" Color="{DynamicResource SystemBaseMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderBackgroundBrush" Color="{DynamicResource SystemAltHighColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderPressedBackgroundBrush" Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderDraggedBackgroundBrush"
Color="{DynamicResource SystemChromeMediumLowColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderBackgroundBrush" Color="{DynamicResource SystemChromeMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderPressedBackgroundBrush"
Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderForegroundBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<StaticResource x:Key="DataGridRowBackgroundBrush" ResourceKey="SystemControlTransparentBrush" /> <StaticResource x:Key="DataGridRowBackgroundBrush" ResourceKey="SystemControlTransparentBrush" />
<SolidColorBrush x:Key="DataGridRowSelectedBackgroundBrush" Color="{DynamicResource SystemAccentColor}" /> <SolidColorBrush x:Key="DataGridRowSelectedBackgroundBrush" Color="{DynamicResource SystemAccentColor}" />
<StaticResource x:Key="DataGridRowSelectedBackgroundOpacity" ResourceKey="ListAccentLowOpacity" /> <StaticResource x:Key="DataGridRowSelectedBackgroundOpacity" ResourceKey="ListAccentLowOpacity" />
@ -29,23 +58,10 @@
<StaticResource x:Key="DataGridRowSelectedHoveredBackgroundOpacity" ResourceKey="ListAccentMediumOpacity" /> <StaticResource x:Key="DataGridRowSelectedHoveredBackgroundOpacity" ResourceKey="ListAccentMediumOpacity" />
<SolidColorBrush x:Key="DataGridRowSelectedUnfocusedBackgroundBrush" Color="{DynamicResource SystemAccentColor}" /> <SolidColorBrush x:Key="DataGridRowSelectedUnfocusedBackgroundBrush" Color="{DynamicResource SystemAccentColor}" />
<StaticResource x:Key="DataGridRowSelectedUnfocusedBackgroundOpacity" ResourceKey="ListAccentLowOpacity" /> <StaticResource x:Key="DataGridRowSelectedUnfocusedBackgroundOpacity" ResourceKey="ListAccentLowOpacity" />
<SolidColorBrush x:Key="DataGridRowSelectedHoveredUnfocusedBackgroundBrush" <SolidColorBrush x:Key="DataGridRowSelectedHoveredUnfocusedBackgroundBrush" Color="{DynamicResource SystemAccentColor}" />
Color="{DynamicResource SystemAccentColor}" />
<StaticResource x:Key="DataGridRowSelectedHoveredUnfocusedBackgroundOpacity" ResourceKey="ListAccentMediumOpacity" /> <StaticResource x:Key="DataGridRowSelectedHoveredUnfocusedBackgroundOpacity" ResourceKey="ListAccentMediumOpacity" />
<SolidColorBrush x:Key="DataGridRowHoveredBackgroundColor" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridRowInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />
<StaticResource x:Key="DataGridCellBackgroundBrush" ResourceKey="SystemControlTransparentBrush" /> <StaticResource x:Key="DataGridCellBackgroundBrush" ResourceKey="SystemControlTransparentBrush" />
<SolidColorBrush x:Key="DataGridCellFocusVisualPrimaryBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridCellFocusVisualSecondaryBrush" Color="{DynamicResource SystemAltMediumColor}" />
<SolidColorBrush x:Key="DataGridCellInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="DataGridGridLinesBrush"
Opacity="0.4"
Color="{DynamicResource SystemBaseMediumLowColor}" />
<StaticResource x:Key="DataGridCurrencyVisualPrimaryBrush" ResourceKey="SystemControlTransparentBrush" /> <StaticResource x:Key="DataGridCurrencyVisualPrimaryBrush" ResourceKey="SystemControlTransparentBrush" />
<SolidColorBrush x:Key="DataGridDetailsPresenterBackgroundBrush"
Color="{DynamicResource SystemChromeMediumLowColor}" />
<StaticResource x:Key="DataGridFillerColumnGridLinesBrush" ResourceKey="SystemControlTransparentBrush" /> <StaticResource x:Key="DataGridFillerColumnGridLinesBrush" ResourceKey="SystemControlTransparentBrush" />
<ControlTheme x:Key="DataGridCellTextBlockTheme" TargetType="TextBlock"> <ControlTheme x:Key="DataGridCellTextBlockTheme" TargetType="TextBlock">
@ -565,5 +581,6 @@
</Style> </Style>
</Style> </Style>
</ControlTheme> </ControlTheme>
</ResourceDictionary>
</Styles.Resources> </Styles.Resources>
</Styles> </Styles>

19
src/Avalonia.Controls/Application.cs

@ -29,7 +29,7 @@ namespace Avalonia
/// method. /// method.
/// - Tracks the lifetime of the application. /// - Tracks the lifetime of the application.
/// </remarks> /// </remarks>
public class Application : AvaloniaObject, IDataContextProvider, IGlobalDataTemplates, IGlobalStyles, IGlobalThemeVariantProvider, IApplicationPlatformEvents public class Application : AvaloniaObject, IDataContextProvider, IGlobalDataTemplates, IGlobalStyles, IThemeVariantHost, IApplicationPlatformEvents
{ {
/// <summary> /// <summary>
/// The application-global data templates. /// The application-global data templates.
@ -50,13 +50,13 @@ namespace Avalonia
public static readonly StyledProperty<object?> DataContextProperty = public static readonly StyledProperty<object?> DataContextProperty =
StyledElement.DataContextProperty.AddOwner<Application>(); StyledElement.DataContextProperty.AddOwner<Application>();
/// <inheritdoc cref="StyledElement.ActualThemeVariantProperty" /> /// <inheritdoc cref="ThemeVariantScope.ActualThemeVariantProperty" />
public static readonly StyledProperty<ThemeVariant> ActualThemeVariantProperty = public static readonly StyledProperty<ThemeVariant> ActualThemeVariantProperty =
StyledElement.ActualThemeVariantProperty.AddOwner<Application>(); ThemeVariantScope.ActualThemeVariantProperty.AddOwner<Application>();
/// <inheritdoc cref="StyledElement.RequestedThemeVariantProperty" /> /// <inheritdoc cref="ThemeVariantScope.RequestedThemeVariantProperty" />
public static readonly StyledProperty<ThemeVariant?> RequestedThemeVariantProperty = public static readonly StyledProperty<ThemeVariant?> RequestedThemeVariantProperty =
StyledElement.RequestedThemeVariantProperty.AddOwner<Application>(); ThemeVariantScope.RequestedThemeVariantProperty.AddOwner<Application>();
/// <inheritdoc/> /// <inheritdoc/>
public event EventHandler<ResourcesChangedEventArgs>? ResourcesChanged; public event EventHandler<ResourcesChangedEventArgs>? ResourcesChanged;
@ -95,11 +95,8 @@ namespace Avalonia
set => SetValue(RequestedThemeVariantProperty, value); set => SetValue(RequestedThemeVariantProperty, value);
} }
/// <inheritdoc cref="StyledElement.ActualThemeVariant"/> /// <inheritdoc />
public ThemeVariant ActualThemeVariant public ThemeVariant ActualThemeVariant => GetValue(ActualThemeVariantProperty);
{
get => GetValue(ActualThemeVariantProperty);
}
/// <summary> /// <summary>
/// Gets the current instance of the <see cref="Application"/> class. /// Gets the current instance of the <see cref="Application"/> class.
@ -256,7 +253,7 @@ namespace Avalonia
.Bind<IAccessKeyHandler>().ToTransient<AccessKeyHandler>() .Bind<IAccessKeyHandler>().ToTransient<AccessKeyHandler>()
.Bind<IGlobalDataTemplates>().ToConstant(this) .Bind<IGlobalDataTemplates>().ToConstant(this)
.Bind<IGlobalStyles>().ToConstant(this) .Bind<IGlobalStyles>().ToConstant(this)
.Bind<IGlobalThemeVariantProvider>().ToConstant(this) .Bind<IThemeVariantHost>().ToConstant(this)
.Bind<IFocusManager>().ToConstant(FocusManager) .Bind<IFocusManager>().ToConstant(FocusManager)
.Bind<IInputManager>().ToConstant(InputManager) .Bind<IInputManager>().ToConstant(InputManager)
.Bind<IKeyboardNavigationHandler>().ToTransient<KeyboardNavigationHandler>() .Bind<IKeyboardNavigationHandler>().ToTransient<KeyboardNavigationHandler>()

2
src/Avalonia.Controls/Control.cs

@ -161,7 +161,7 @@ namespace Avalonia.Controls
get => GetValue(TagProperty); get => GetValue(TagProperty);
set => SetValue(TagProperty, value); set => SetValue(TagProperty, value);
} }
/// <summary> /// <summary>
/// Occurs when the user has completed a context input gesture, such as a right-click. /// Occurs when the user has completed a context input gesture, such as a right-click.
/// </summary> /// </summary>

9
src/Avalonia.Controls/Primitives/Popup.cs

@ -387,6 +387,15 @@ namespace Avalonia.Controls.Primitives
popupHost.Transform = null; popupHost.Transform = null;
} }
if (popupHost is PopupRoot topLevelPopup)
{
topLevelPopup
.Bind(
ThemeVariantScope.ActualThemeVariantProperty,
this.GetBindingObservable(ThemeVariantScope.ActualThemeVariantProperty))
.DisposeWith(handlerCleanup);
}
UpdateHostPosition(popupHost, placementTarget); UpdateHostPosition(popupHost, placementTarget);
SubscribeToEventHandler<IPopupHost, EventHandler<TemplateAppliedEventArgs>>(popupHost, RootTemplateApplied, SubscribeToEventHandler<IPopupHost, EventHandler<TemplateAppliedEventArgs>>(popupHost, RootTemplateApplied,

8
src/Avalonia.Controls/ThemeVariantScope.cs

@ -7,6 +7,14 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
public class ThemeVariantScope : Decorator public class ThemeVariantScope : Decorator
{ {
/// <inheritdoc cref="ThemeVariant.ActualThemeVariantProperty" />
public static readonly StyledProperty<ThemeVariant> ActualThemeVariantProperty =
ThemeVariant.ActualThemeVariantProperty.AddOwner<ThemeVariantScope>();
/// <inheritdoc cref="ThemeVariant.RequestedThemeVariantProperty" />
public static readonly StyledProperty<ThemeVariant?> RequestedThemeVariantProperty =
ThemeVariant.RequestedThemeVariantProperty.AddOwner<ThemeVariantScope>();
/// <summary> /// <summary>
/// Gets or sets the UI theme variant that is used by the control (and its child elements) for resource determination. /// Gets or sets the UI theme variant that is used by the control (and its child elements) for resource determination.
/// The UI theme you specify with ThemeVariant can override the app-level ThemeVariant. /// The UI theme you specify with ThemeVariant can override the app-level ThemeVariant.

14
src/Avalonia.Controls/TopLevel.cs

@ -80,6 +80,14 @@ namespace Avalonia.Controls
public static readonly StyledProperty<IBrush> TransparencyBackgroundFallbackProperty = public static readonly StyledProperty<IBrush> TransparencyBackgroundFallbackProperty =
AvaloniaProperty.Register<TopLevel, IBrush>(nameof(TransparencyBackgroundFallback), Brushes.White); AvaloniaProperty.Register<TopLevel, IBrush>(nameof(TransparencyBackgroundFallback), Brushes.White);
/// <inheritdoc cref="ThemeVariantScope.ActualThemeVariantProperty" />
public static readonly StyledProperty<ThemeVariant> ActualThemeVariantProperty =
ThemeVariantScope.ActualThemeVariantProperty.AddOwner<Application>();
/// <inheritdoc cref="ThemeVariantScope.RequestedThemeVariantProperty" />
public static readonly StyledProperty<ThemeVariant?> RequestedThemeVariantProperty =
ThemeVariantScope.RequestedThemeVariantProperty.AddOwner<Application>();
/// <summary> /// <summary>
/// Defines the <see cref="BackRequested"/> event. /// Defines the <see cref="BackRequested"/> event.
/// </summary> /// </summary>
@ -96,7 +104,7 @@ namespace Avalonia.Controls
private readonly IAccessKeyHandler? _accessKeyHandler; private readonly IAccessKeyHandler? _accessKeyHandler;
private readonly IKeyboardNavigationHandler? _keyboardNavigationHandler; private readonly IKeyboardNavigationHandler? _keyboardNavigationHandler;
private readonly IGlobalStyles? _globalStyles; private readonly IGlobalStyles? _globalStyles;
private readonly IGlobalThemeVariantProvider? _applicationThemeHost; private readonly IThemeVariantHost? _applicationThemeHost;
private readonly PointerOverPreProcessor? _pointerOverPreProcessor; private readonly PointerOverPreProcessor? _pointerOverPreProcessor;
private readonly IDisposable? _pointerOverPreProcessorSubscription; private readonly IDisposable? _pointerOverPreProcessorSubscription;
private readonly IDisposable? _backGestureSubscription; private readonly IDisposable? _backGestureSubscription;
@ -147,7 +155,7 @@ namespace Avalonia.Controls
_inputManager = TryGetService<IInputManager>(dependencyResolver); _inputManager = TryGetService<IInputManager>(dependencyResolver);
_keyboardNavigationHandler = TryGetService<IKeyboardNavigationHandler>(dependencyResolver); _keyboardNavigationHandler = TryGetService<IKeyboardNavigationHandler>(dependencyResolver);
_globalStyles = TryGetService<IGlobalStyles>(dependencyResolver); _globalStyles = TryGetService<IGlobalStyles>(dependencyResolver);
_applicationThemeHost = TryGetService<IGlobalThemeVariantProvider>(dependencyResolver); _applicationThemeHost = TryGetService<IThemeVariantHost>(dependencyResolver);
Renderer = impl.CreateRenderer(this); Renderer = impl.CreateRenderer(this);
Renderer.SceneInvalidated += SceneInvalidated; Renderer.SceneInvalidated += SceneInvalidated;
@ -642,7 +650,7 @@ namespace Avalonia.Controls
private void GlobalActualThemeVariantChanged(object? sender, EventArgs e) private void GlobalActualThemeVariantChanged(object? sender, EventArgs e)
{ {
SetValue(ActualThemeVariantProperty, ((IGlobalThemeVariantProvider)sender!).ActualThemeVariant, BindingPriority.Template); SetValue(ActualThemeVariantProperty, ((IThemeVariantHost)sender!).ActualThemeVariant, BindingPriority.Template);
} }
private void SceneInvalidated(object? sender, SceneInvalidatedEventArgs e) private void SceneInvalidated(object? sender, SceneInvalidatedEventArgs e)

2
src/Avalonia.Diagnostics/Diagnostics/Controls/Application.cs

@ -14,7 +14,7 @@ namespace Avalonia.Diagnostics.Controls
public event EventHandler? Closed; public event EventHandler? Closed;
public static readonly StyledProperty<ThemeVariant?> RequestedThemeVariantProperty = public static readonly StyledProperty<ThemeVariant?> RequestedThemeVariantProperty =
StyledElement.RequestedThemeVariantProperty.AddOwner<Application>(); ThemeVariantScope.RequestedThemeVariantProperty.AddOwner<Application>();
public Application(Avalonia.Application application) public Application(Avalonia.Application application)
{ {

104
src/Avalonia.Themes.Simple/Controls/SplitButton.xaml

@ -2,8 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:Avalonia.Controls.Converters"> xmlns:converters="using:Avalonia.Controls.Converters">
<!-- This style is heavily based on the Fluent v1 style. <!-- This style is based on the Fluent v1 style. -->
The base resources are switched out along with a few minor changes such as Padding, CornerRadius. -->
<Design.PreviewWith> <Design.PreviewWith>
<Border Padding="20"> <Border Padding="20">
@ -26,37 +25,7 @@
<converters:CornerRadiusFilterConverter x:Key="RightCornerRadiusFilterConverter" Filter="TopRight, BottomRight" /> <converters:CornerRadiusFilterConverter x:Key="RightCornerRadiusFilterConverter" Filter="TopRight, BottomRight" />
<converters:CornerRadiusFilterConverter x:Key="BottomCornerRadiusFilterConverter" Filter="BottomLeft, BottomRight" /> <converters:CornerRadiusFilterConverter x:Key="BottomCornerRadiusFilterConverter" Filter="BottomLeft, BottomRight" />
<converters:CornerRadiusFilterConverter x:Key="LeftCornerRadiusFilterConverter" Filter="TopLeft, BottomLeft" /> <converters:CornerRadiusFilterConverter x:Key="LeftCornerRadiusFilterConverter" Filter="TopLeft, BottomLeft" />
<SolidColorBrush x:Key="SplitButtonBackground" Color="{DynamicResource ThemeControlMidColor}" />
<SolidColorBrush x:Key="SplitButtonBackgroundPointerOver" Color="{DynamicResource ThemeControlMidColor}" />
<SolidColorBrush x:Key="SplitButtonBackgroundPressed" Color="{DynamicResource ThemeBorderHighColor}" />
<SolidColorBrush x:Key="SplitButtonBackgroundDisabled" Color="{DynamicResource ThemeControlMidColor}"
Opacity="{DynamicResource ThemeDisabledOpacity}" />
<SolidColorBrush x:Key="SplitButtonBackgroundChecked" Color="{DynamicResource ThemeBorderHighColor}" />
<SolidColorBrush x:Key="SplitButtonBackgroundCheckedPointerOver" Color="{DynamicResource ThemeBorderHighColor}" />
<SolidColorBrush x:Key="SplitButtonBackgroundCheckedPressed" Color="{DynamicResource ThemeBorderHighColor}" />
<SolidColorBrush x:Key="SplitButtonBackgroundCheckedDisabled" Color="{DynamicResource ThemeControlHighColor}"
Opacity="{DynamicResource ThemeDisabledOpacity}" />
<SolidColorBrush x:Key="SplitButtonForeground" Color="{DynamicResource ThemeForegroundColor}" />
<SolidColorBrush x:Key="SplitButtonForegroundPointerOver" Color="{DynamicResource ThemeForegroundColor}" />
<SolidColorBrush x:Key="SplitButtonForegroundPressed" Color="{DynamicResource ThemeForegroundColor}" />
<SolidColorBrush x:Key="SplitButtonForegroundDisabled" Color="{DynamicResource ThemeForegroundColor}" />
<SolidColorBrush x:Key="SplitButtonForegroundChecked" Color="{DynamicResource ThemeForegroundColor}" />
<SolidColorBrush x:Key="SplitButtonForegroundCheckedPointerOver" Color="{DynamicResource ThemeForegroundColor}" />
<SolidColorBrush x:Key="SplitButtonForegroundCheckedPressed" Color="{DynamicResource ThemeForegroundColor}" />
<SolidColorBrush x:Key="SplitButtonForegroundCheckedDisabled" Color="{DynamicResource ThemeForegroundColor}" />
<SolidColorBrush x:Key="SplitButtonBorderBrush" Color="{DynamicResource ThemeBorderLowColor}" />
<SolidColorBrush x:Key="SplitButtonBorderBrushPointerOver" Color="{DynamicResource ThemeBorderMidColor}" />
<SolidColorBrush x:Key="SplitButtonBorderBrushPressed" Color="{DynamicResource ThemeBorderLowColor}" />
<SolidColorBrush x:Key="SplitButtonBorderBrushDisabled" Color="{DynamicResource ThemeBorderLowColor}" />
<SolidColorBrush x:Key="SplitButtonBorderBrushChecked" Color="{DynamicResource ThemeBorderMidColor}" />
<SolidColorBrush x:Key="SplitButtonBorderBrushCheckedPointerOver" Color="{DynamicResource ThemeBorderMidColor}" />
<SolidColorBrush x:Key="SplitButtonBorderBrushCheckedPressed" Color="{DynamicResource ThemeControlHighColor}" />
<SolidColorBrush x:Key="SplitButtonBorderBrushCheckedDisabled" Color="{DynamicResource ThemeControlMidColor}"
Opacity="{DynamicResource ThemeDisabledOpacity}" />
<ControlTheme x:Key="SimpleSplitButtonComponent" TargetType="Button"> <ControlTheme x:Key="SimpleSplitButtonComponent" TargetType="Button">
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
@ -75,66 +44,75 @@
</Setter> </Setter>
<Style Selector="^:pointerover /template/ ContentPresenter"> <Style Selector="^:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SplitButtonBackgroundPointerOver}" /> <Setter Property="Background" Value="{DynamicResource ThemeControlMidColor}" />
<Setter Property="BorderBrush" Value="{DynamicResource SplitButtonBorderBrushPointerOver}" /> <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidColor}" />
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundPointerOver}" /> <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
</Style> </Style>
<Style Selector="^:pressed /template/ ContentPresenter"> <Style Selector="^:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SplitButtonBackgroundPressed}" /> <Setter Property="Background" Value="{DynamicResource ThemeBorderHighColor}" />
<Setter Property="BorderBrush" Value="{DynamicResource SplitButtonBorderBrushPressed}" /> <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLowColor}" />
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundPressed}" /> <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
</Style> </Style>
<Style Selector="^:disabled /template/ ContentPresenter"> <Style Selector="^:disabled /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SplitButtonBackgroundDisabled}" /> <Setter Property="Background">
<Setter Property="BorderBrush" Value="{DynamicResource SplitButtonBorderBrushDisabled}" /> <SolidColorBrush Color="{DynamicResource ThemeControlMidColor}"
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundDisabled}" /> Opacity="{DynamicResource ThemeDisabledOpacity}" />
</Setter>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLowColor}" />
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
</Style> </Style>
<Style Selector="^[Tag=flyout-open] /template/ ContentPresenter"> <Style Selector="^[Tag=flyout-open] /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SplitButtonBackgroundPressed}" /> <Setter Property="Background" Value="{DynamicResource ThemeBorderHighColor}" />
<Setter Property="BorderBrush" Value="{DynamicResource SplitButtonBorderBrushPressed}" /> <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLowColor}" />
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundPressed}" /> <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
</Style> </Style>
<Style Selector="^[Tag=checked]"> <Style Selector="^[Tag=checked]">
<Style Selector="^ /template/ ContentPresenter"> <Style Selector="^ /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SplitButtonBackgroundChecked}" /> <Setter Property="Background" Value="{DynamicResource ThemeBorderHighColor}" />
<Setter Property="BorderBrush" Value="{DynamicResource SplitButtonBorderBrushChecked}" /> <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidColor}" />
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundChecked}" /> <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
</Style> </Style>
<Style Selector="^:pointerover /template/ ContentPresenter"> <Style Selector="^:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SplitButtonBackgroundCheckedPointerOver}" /> <Setter Property="Background" Value="{DynamicResource ThemeBorderHighColor}" />
<Setter Property="BorderBrush" Value="{DynamicResource SplitButtonBorderBrushCheckedPointerOver}" /> <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidColor}" />
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPointerOver}" /> <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
</Style> </Style>
<Style Selector="^:pressed /template/ ContentPresenter"> <Style Selector="^:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SplitButtonBackgroundCheckedPressed}" /> <Setter Property="Background" Value="{DynamicResource ThemeBorderHighColor}" />
<Setter Property="BorderBrush" Value="{DynamicResource SplitButtonBorderBrushCheckedPressed}" /> <Setter Property="BorderBrush" Value="{DynamicResource ThemeControlHighColor}" />
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPressed}" /> <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
</Style> </Style>
<Style Selector="^:disabled /template/ ContentPresenter"> <Style Selector="^:disabled /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SplitButtonBackgroundCheckedDisabled}" /> <Setter Property="Background">
<Setter Property="BorderBrush" Value="{DynamicResource SplitButtonBorderBrushCheckedDisabled}" /> <SolidColorBrush Color="{DynamicResource ThemeControlHighColor}"
<Setter Property="TextElement.Foreground" Value="{DynamicResource SplitButtonForegroundCheckedDisabled}" /> Opacity="{DynamicResource ThemeDisabledOpacity}" />
</Setter>
<Setter Property="BorderBrush">
<SolidColorBrush Color="{DynamicResource ThemeControlMidColor}"
Opacity="{DynamicResource ThemeDisabledOpacity}" />
</Setter>
<Setter Property="TextElement.Foreground" Value="{DynamicResource ThemeForegroundColor}" />
</Style> </Style>
</Style> </Style>
<Style Selector="^[Tag=checked-flyout-open] /template/ ContentPresenter"> <Style Selector="^[Tag=checked-flyout-open] /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SplitButtonBackgroundCheckedPressed}" /> <Setter Property="Background" Value="{DynamicResource ThemeBorderHighColor}" />
<Setter Property="BorderBrush" Value="{DynamicResource SplitButtonBorderBrushCheckedPressed}" /> <Setter Property="BorderBrush" Value="{DynamicResource ThemeControlHighColor}" />
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPressed}" /> <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
</Style> </Style>
</ControlTheme> </ControlTheme>
<ControlTheme x:Key="{x:Type SplitButton}" TargetType="SplitButton"> <ControlTheme x:Key="{x:Type SplitButton}" TargetType="SplitButton">
<Setter Property="Background" Value="{DynamicResource SplitButtonBackground}" /> <Setter Property="Background" Value="{DynamicResource ThemeControlMidColor}" />
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForeground}" /> <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
<Setter Property="BorderBrush" Value="{DynamicResource SplitButtonBorderBrush}" /> <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLowColor}" />
<Setter Property="BorderThickness" Value="{DynamicResource SplitButtonBorderThemeThickness}" /> <Setter Property="BorderThickness" Value="{DynamicResource SplitButtonBorderThemeThickness}" />
<Setter Property="MinHeight" Value="{DynamicResource SplitButtonMinHeight}" /> <Setter Property="MinHeight" Value="{DynamicResource SplitButtonMinHeight}" />
<Setter Property="HorizontalAlignment" Value="Left" /> <Setter Property="HorizontalAlignment" Value="Left" />

6
src/Avalonia.Themes.Simple/Controls/SplitView.xaml

@ -17,8 +17,6 @@
<x:Double x:Key="SplitViewOpenPaneThemeLength">320</x:Double> <x:Double x:Key="SplitViewOpenPaneThemeLength">320</x:Double>
<x:Double x:Key="SplitViewCompactPaneThemeLength">48</x:Double> <x:Double x:Key="SplitViewCompactPaneThemeLength">48</x:Double>
<SolidColorBrush x:Key="SplitViewLightDismissOverlayBackground" Color="{DynamicResource ThemeControlLowColor}"
Opacity="0.6" />
<sys:TimeSpan x:Key="SplitViewPaneAnimationOpenDuration">00:00:00.2</sys:TimeSpan> <sys:TimeSpan x:Key="SplitViewPaneAnimationOpenDuration">00:00:00.2</sys:TimeSpan>
<sys:TimeSpan x:Key="SplitViewPaneAnimationCloseDuration">00:00:00.1</sys:TimeSpan> <sys:TimeSpan x:Key="SplitViewPaneAnimationCloseDuration">00:00:00.1</sys:TimeSpan>
<Easing x:Key="SplitViewPaneAnimationEasing">0.1,0.9,0.2,1.0</Easing> <Easing x:Key="SplitViewPaneAnimationEasing">0.1,0.9,0.2,1.0</Easing>
@ -240,7 +238,9 @@
<Setter Property="Fill" Value="Transparent" /> <Setter Property="Fill" Value="Transparent" />
</Style> </Style>
<Style Selector="^:lightdismiss /template/ Rectangle#LightDismissLayer"> <Style Selector="^:lightdismiss /template/ Rectangle#LightDismissLayer">
<Setter Property="Fill" Value="{DynamicResource SplitViewLightDismissOverlayBackground}" /> <Setter Property="Fill">
<SolidColorBrush Color="{DynamicResource ThemeControlLowColor}" Opacity="0.6" />
</Setter>
</Style> </Style>
<Style Selector="^:overlay:open /template/ Rectangle#LightDismissLayer"> <Style Selector="^:overlay:open /template/ Rectangle#LightDismissLayer">

91
src/Avalonia.Themes.Simple/Controls/ToggleSwitch.xaml

@ -36,43 +36,10 @@
<x:Double x:Key="ToggleSwitchThemeMinWidth">0</x:Double> <x:Double x:Key="ToggleSwitchThemeMinWidth">0</x:Double>
<Thickness x:Key="ToggleSwitchOnStrokeThickness">0</Thickness> <Thickness x:Key="ToggleSwitchOnStrokeThickness">0</Thickness>
<Thickness x:Key="ToggleSwitchOuterBorderStrokeThickness">1</Thickness> <Thickness x:Key="ToggleSwitchOuterBorderStrokeThickness">1</Thickness>
<SolidColorBrush x:Key="ToggleSwitchContentForeground" Color="{DynamicResource ThemeForegroundColor}" />
<SolidColorBrush x:Key="ToggleSwitchContentForegroundDisabled" Color="{DynamicResource ThemeForegroundLowColor}" />
<SolidColorBrush x:Key="ToggleSwitchHeaderForeground" Color="{DynamicResource ThemeForegroundColor}" />
<SolidColorBrush x:Key="ToggleSwitchHeaderForegroundDisabled" Color="{DynamicResource ThemeForegroundLowColor}" />
<SolidColorBrush x:Key="ToggleSwitchContainerBackground" Color="Transparent" />
<SolidColorBrush x:Key="ToggleSwitchContainerBackgroundPointerOver" Color="Transparent" />
<SolidColorBrush x:Key="ToggleSwitchContainerBackgroundPressed" Color="Transparent" />
<SolidColorBrush x:Key="ToggleSwitchContainerBackgroundDisabled" Color="Transparent" />
<SolidColorBrush x:Key="ToggleSwitchFillOff" Color="Transparent" />
<SolidColorBrush x:Key="ToggleSwitchFillOffPointerOver" Color="Transparent" />
<SolidColorBrush x:Key="ToggleSwitchFillOffPressed" Color="{DynamicResource ThemeControlMidHighColor}" />
<SolidColorBrush x:Key="ToggleSwitchFillOffDisabled" Color="Transparent" />
<SolidColorBrush x:Key="ToggleSwitchStrokeOff" Color="{DynamicResource ThemeBorderMidColor}" />
<SolidColorBrush x:Key="ToggleSwitchStrokeOffPointerOver" Color="{DynamicResource ThemeBorderHighColor}" />
<SolidColorBrush x:Key="ToggleSwitchStrokeOffPressed" Color="{DynamicResource ThemeBorderHighColor}" />
<SolidColorBrush x:Key="ToggleSwitchStrokeOffDisabled" Color="{DynamicResource ThemeForegroundLowColor}" />
<SolidColorBrush x:Key="ToggleSwitchFillOn" Color="{DynamicResource ThemeAccentColor}" />
<SolidColorBrush x:Key="ToggleSwitchFillOnPointerOver" Color="{DynamicResource ThemeAccentColor2}" />
<SolidColorBrush x:Key="ToggleSwitchFillOnPressed" Color="{DynamicResource ThemeAccentColor3}" />
<SolidColorBrush x:Key="ToggleSwitchFillOnDisabled" Color="{DynamicResource ThemeForegroundLowColor}" />
<SolidColorBrush x:Key="ToggleSwitchStrokeOn" Color="{DynamicResource ThemeAccentColor}" />
<SolidColorBrush x:Key="ToggleSwitchStrokeOnPointerOver" Color="{DynamicResource ThemeAccentColor2}" />
<SolidColorBrush x:Key="ToggleSwitchStrokeOnPressed" Color="{DynamicResource ThemeAccentColor3}" />
<SolidColorBrush x:Key="ToggleSwitchStrokeOnDisabled" Color="{DynamicResource ThemeForegroundLowColor}" />
<SolidColorBrush x:Key="ToggleSwitchKnobFillOff" Color="{DynamicResource ThemeBorderMidColor}" />
<SolidColorBrush x:Key="ToggleSwitchKnobFillOffPointerOver" Color="{DynamicResource ThemeBorderHighColor}" />
<SolidColorBrush x:Key="ToggleSwitchKnobFillOffPressed" Color="{DynamicResource ThemeBorderHighColor}" />
<SolidColorBrush x:Key="ToggleSwitchKnobFillOffDisabled" Color="{DynamicResource ThemeForegroundLowColor}" />
<SolidColorBrush x:Key="ToggleSwitchKnobFillOn" Color="{DynamicResource HighlightForegroundColor}" />
<SolidColorBrush x:Key="ToggleSwitchKnobFillOnPointerOver" Color="{DynamicResource HighlightForegroundColor}" />
<SolidColorBrush x:Key="ToggleSwitchKnobFillOnPressed" Color="{DynamicResource HighlightForegroundColor}" />
<SolidColorBrush x:Key="ToggleSwitchKnobFillOnDisabled" Color="{DynamicResource HighlightForegroundColor}" />
<ControlTheme x:Key="{x:Type ToggleSwitch}" <ControlTheme x:Key="{x:Type ToggleSwitch}"
TargetType="ToggleSwitch"> TargetType="ToggleSwitch">
<Setter Property="Foreground" Value="{DynamicResource ToggleSwitchContentForeground}" /> <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
<Setter Property="HorizontalAlignment" Value="Left" /> <Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Left" /> <Setter Property="HorizontalContentAlignment" Value="Left" />
@ -111,7 +78,7 @@
<Grid x:Name="SwitchAreaGrid" <Grid x:Name="SwitchAreaGrid"
Grid.RowSpan="3" Grid.RowSpan="3"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
Background="{DynamicResource ToggleSwitchContainerBackground}" Background="Transparent"
TemplatedControl.IsTemplateFocusTarget="True" TemplatedControl.IsTemplateFocusTarget="True"
Margin="0,5" /> Margin="0,5" />
@ -136,8 +103,8 @@
Height="20" Height="20"
Width="40" Width="40"
CornerRadius="10" CornerRadius="10"
Background="{DynamicResource ToggleSwitchFillOff}" Background="Transparent"
BorderBrush="{DynamicResource ToggleSwitchStrokeOff}" BorderBrush="{DynamicResource ThemeBorderMidColor}"
BorderThickness="{DynamicResource ToggleSwitchOuterBorderStrokeThickness}" /> BorderThickness="{DynamicResource ToggleSwitchOuterBorderStrokeThickness}" />
<Border x:Name="SwitchKnobBounds" <Border x:Name="SwitchKnobBounds"
@ -145,8 +112,8 @@
Height="20" Height="20"
Width="40" Width="40"
CornerRadius="10" CornerRadius="10"
Background="{DynamicResource ToggleSwitchFillOn}" Background="{DynamicResource ThemeAccentColor}"
BorderBrush="{DynamicResource ToggleSwitchStrokeOn}" BorderBrush="{DynamicResource ThemeAccentColor}"
BorderThickness="{DynamicResource ToggleSwitchOnStrokeThickness}" /> BorderThickness="{DynamicResource ToggleSwitchOnStrokeThickness}" />
<Canvas x:Name="PART_SwitchKnob" Grid.Row="1" <Canvas x:Name="PART_SwitchKnob" Grid.Row="1"
@ -162,11 +129,11 @@
</Grid.Transitions> </Grid.Transitions>
<Ellipse x:Name="SwitchKnobOn" <Ellipse x:Name="SwitchKnobOn"
Fill="{DynamicResource ToggleSwitchKnobFillOn}" Fill="{DynamicResource HighlightForegroundColor}"
Width="10" Height="10" /> Width="10" Height="10" />
<Ellipse x:Name="SwitchKnobOff" <Ellipse x:Name="SwitchKnobOff"
Fill="{DynamicResource ToggleSwitchKnobFillOff}" Fill="{DynamicResource ThemeBorderMidColor}"
Width="10" Height="10" /> Width="10" Height="10" />
</Grid> </Grid>
</Canvas> </Canvas>
@ -181,71 +148,71 @@
<!-- PointerOverState --> <!-- PointerOverState -->
<Style Selector="^:pointerover /template/ Border#OuterBorder"> <Style Selector="^:pointerover /template/ Border#OuterBorder">
<Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOffPointerOver}" /> <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderHighColor}" />
<Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOffPointerOver}" /> <Setter Property="Background" Value="Transparent" />
</Style> </Style>
<Style Selector="^:pointerover /template/ Ellipse#SwitchKnobOff"> <Style Selector="^:pointerover /template/ Ellipse#SwitchKnobOff">
<Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOffPointerOver}" /> <Setter Property="Fill" Value="{DynamicResource ThemeBorderHighColor}" />
</Style> </Style>
<Style Selector="^:pointerover /template/ Ellipse#SwitchKnobOn"> <Style Selector="^:pointerover /template/ Ellipse#SwitchKnobOn">
<Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOnPointerOver}" /> <Setter Property="Fill" Value="{DynamicResource HighlightForegroundColor}" />
</Style> </Style>
<Style Selector="^:pointerover /template/ Border#SwitchKnobBounds"> <Style Selector="^:pointerover /template/ Border#SwitchKnobBounds">
<Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOnPointerOver}" /> <Setter Property="Background" Value="{DynamicResource ThemeAccentColor2}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOnPointerOver}" /> <Setter Property="BorderBrush" Value="{DynamicResource ThemeAccentColor2}" />
</Style> </Style>
<Style Selector="^:pointerover /template/ Grid#SwitchAreaGrid"> <Style Selector="^:pointerover /template/ Grid#SwitchAreaGrid">
<Setter Property="Background" Value="{DynamicResource ToggleSwitchContainerBackgroundPointerOver}" /> <Setter Property="Background" Value="Transparent" />
</Style> </Style>
<!-- PressedState --> <!-- PressedState -->
<Style Selector="^:pressed /template/ Border#OuterBorder"> <Style Selector="^:pressed /template/ Border#OuterBorder">
<Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOffPressed}" /> <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderHighColor}" />
<Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOffPressed}" /> <Setter Property="Background" Value="{DynamicResource ThemeControlMidHighColor}" />
</Style> </Style>
<Style Selector="^:pressed /template/ Border#SwitchKnobBounds"> <Style Selector="^:pressed /template/ Border#SwitchKnobBounds">
<Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOnPressed}" /> <Setter Property="Background" Value="{DynamicResource ThemeAccentColor3}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOnPressed}" /> <Setter Property="BorderBrush" Value="{DynamicResource ThemeAccentColor3}" />
</Style> </Style>
<Style Selector="^:pressed /template/ Ellipse#SwitchKnobOff"> <Style Selector="^:pressed /template/ Ellipse#SwitchKnobOff">
<Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOffPressed}" /> <Setter Property="Fill" Value="{DynamicResource ThemeBorderHighColor}" />
</Style> </Style>
<Style Selector="^:pressed /template/ Ellipse#SwitchKnobOn"> <Style Selector="^:pressed /template/ Ellipse#SwitchKnobOn">
<Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOnPressed}" /> <Setter Property="Fill" Value="{DynamicResource HighlightForegroundColor}" />
</Style> </Style>
<Style Selector="^:pressed /template/ Grid#SwitchAreaGrid"> <Style Selector="^:pressed /template/ Grid#SwitchAreaGrid">
<Setter Property="Background" Value="{DynamicResource ToggleSwitchContainerBackgroundPressed}" /> <Setter Property="Background" Value="Transparent" />
</Style> </Style>
<!-- DisabledState --> <!-- DisabledState -->
<Style Selector="^:disabled"> <Style Selector="^:disabled">
<Setter Property="Foreground" Value="{DynamicResource ToggleSwitchHeaderForegroundDisabled}" /> <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundLowColor}" />
</Style> </Style>
<Style Selector="^:disabled /template/ Border#OuterBorder"> <Style Selector="^:disabled /template/ Border#OuterBorder">
<Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOffDisabled}" /> <Setter Property="BorderBrush" Value="{DynamicResource ThemeForegroundLowColor}" />
<Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOffDisabled}" /> <Setter Property="Background" Value="Transparent" />
</Style> </Style>
<Style Selector="^:disabled /template/ Ellipse#SwitchKnobOff"> <Style Selector="^:disabled /template/ Ellipse#SwitchKnobOff">
<Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOffDisabled}" /> <Setter Property="Fill" Value="{DynamicResource ThemeForegroundLowColor}" />
</Style> </Style>
<Style Selector="^:disabled /template/ Ellipse#SwitchKnobOn"> <Style Selector="^:disabled /template/ Ellipse#SwitchKnobOn">
<Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOnDisabled}" /> <Setter Property="Fill" Value="{DynamicResource HighlightForegroundColor}" />
</Style> </Style>
<Style Selector="^:disabled /template/ Border#SwitchKnobBounds"> <Style Selector="^:disabled /template/ Border#SwitchKnobBounds">
<Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOnDisabled}" /> <Setter Property="Background" Value="{DynamicResource ThemeForegroundLowColor}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOnDisabled}" /> <Setter Property="BorderBrush" Value="{DynamicResource ThemeForegroundLowColor}" />
</Style> </Style>
<!-- CheckedState --> <!-- CheckedState -->

2
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs

@ -34,7 +34,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
var stack = serviceProvider.GetService<IAvaloniaXamlIlParentStackProvider>(); var stack = serviceProvider.GetService<IAvaloniaXamlIlParentStackProvider>();
var provideTarget = serviceProvider.GetService<IProvideValueTarget>(); var provideTarget = serviceProvider.GetService<IProvideValueTarget>();
var themeVariant = (provideTarget.TargetObject as StyledElement)?.ActualThemeVariant; var themeVariant = (provideTarget.TargetObject as IThemeVariantHost)?.ActualThemeVariant;
var targetType = provideTarget.TargetProperty switch var targetType = provideTarget.TargetProperty switch
{ {

77
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ThemeDictionariesTests.cs

@ -1,8 +1,12 @@
using Avalonia.Controls; using System.Linq;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Markup.Data; using Avalonia.Markup.Data;
using Avalonia.Markup.Xaml.MarkupExtensions; using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Styling; using Avalonia.Styling;
using Avalonia.UnitTests;
using Moq; using Moq;
using Xunit; using Xunit;
@ -185,9 +189,9 @@ public class ThemeDictionariesTests : XamlTestBase
{ {
using (AvaloniaLocator.EnterScope()) using (AvaloniaLocator.EnterScope())
{ {
var applicationThemeHost = new Mock<IGlobalThemeVariantProvider>(); var applicationThemeHost = new Mock<IThemeVariantHost>();
applicationThemeHost.SetupGet(h => h.ActualThemeVariant).Returns(ThemeVariant.Dark); applicationThemeHost.SetupGet(h => h.ActualThemeVariant).Returns(ThemeVariant.Dark);
AvaloniaLocator.CurrentMutable.Bind<IGlobalThemeVariantProvider>().ToConstant(applicationThemeHost.Object); AvaloniaLocator.CurrentMutable.Bind<IThemeVariantHost>().ToConstant(applicationThemeHost.Object);
var themeVariantScope = (ThemeVariantScope)AvaloniaRuntimeXamlLoader.Load(@" var themeVariantScope = (ThemeVariantScope)AvaloniaRuntimeXamlLoader.Load(@"
<ThemeVariantScope xmlns='https://github.com/avaloniaui' <ThemeVariantScope xmlns='https://github.com/avaloniaui'
@ -444,4 +448,71 @@ public class ThemeDictionariesTests : XamlTestBase
Assert.Equal(Colors.Black, ((ISolidColorBrush)border.Background)!.Color); Assert.Equal(Colors.Black, ((ISolidColorBrush)border.Background)!.Color);
} }
[Fact]
public void Theme_Switch_Works_In_Nested_Scope()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
RequestedThemeVariant='Dark'>
<ThemeVariantScope Name='Scope'>
<TextBlock Name='Text' />
</ThemeVariantScope>
</Window>");
window.ApplyTemplate();
var scope = window.FindControl<ThemeVariantScope>("Scope")!;
var text = window.FindControl<TextBlock>("Text")!;
Assert.Equal(ThemeVariant.Dark, text.ActualThemeVariant);
Assert.Equal(Color.Parse("#dedede"), ((ISolidColorBrush)text.Foreground!).Color);
scope.RequestedThemeVariant = ThemeVariant.Light;
Assert.Equal(ThemeVariant.Light, text.ActualThemeVariant);
Assert.Equal(Colors.Black, ((ISolidColorBrush)text.Foreground!).Color);
}
}
[Fact]
public void Theme_Switch_Works_In_With_Popup()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<ThemeVariantScope Name='Scope' RequestedThemeVariant='Dark'>
<Popup Name='Popup'>
<Border Width='100' Height='100'
Background='{DynamicResource ThemeBackgroundBrush}'>
</Border>
</Popup>
</ThemeVariantScope>
</Window>");
window.Show();
var scope = window.FindControl<ThemeVariantScope>("Scope")!;
var popup = window.FindControl<Popup>("Popup")!;
popup.IsOpen = true;
var border = (Border)popup.Child!;
Assert.Equal(ThemeVariant.Dark, popup.ActualThemeVariant);
Assert.Equal(ThemeVariant.Dark, border.ActualThemeVariant);
Assert.Equal(Color.Parse("#282828"), ((ISolidColorBrush)border.Background!).Color);
scope.RequestedThemeVariant = ThemeVariant.Light;
Assert.Equal(ThemeVariant.Light, popup.ActualThemeVariant);
Assert.Equal(ThemeVariant.Light, border.ActualThemeVariant);
Assert.Equal(Colors.White, ((ISolidColorBrush)border.Background!).Color);
}
}
}
} }

Loading…
Cancel
Save