* Implement AvaloniaObject on ResourceProvider

* ColorPaletteResources and ColorPaletteResourcesCollection should inherit ResourceProvider

* Use ResourceProvider in tests too

* Adjust API diff

---------

Co-authored-by: Steven Kirk <grokys@users.noreply.github.com>
This commit is contained in:
Max Katz 2024-09-12 16:07:13 -07:00 коммит произвёл GitHub
Родитель 932f54316b
Коммит c50e731d8d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
7 изменённых файлов: 130 добавлений и 57 удалений

Просмотреть файл

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/en-us/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0007</DiagnosticId>
<Target>T:Avalonia.Themes.Fluent.ColorPaletteResources</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Themes.Fluent.ColorPaletteResources</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
</Suppressions>

Просмотреть файл

@ -7,7 +7,7 @@ namespace Avalonia.Controls;
/// Base implementation for IResourceProvider interface.
/// Includes Owner property management.
/// </summary>
public abstract class ResourceProvider : IResourceProvider
public abstract class ResourceProvider : AvaloniaObject, IResourceProvider
{
private IResourceHost? _owner;

Просмотреть файл

@ -14,13 +14,13 @@ namespace Avalonia.Themes.Fluent;
/// <remarks>
/// This class can only be used in <see cref="FluentTheme.Palettes"/>.
/// </remarks>
public partial class ColorPaletteResources : AvaloniaObject, IResourceNode
public partial class ColorPaletteResources : ResourceProvider
{
private readonly Dictionary<string, Color> _colors = new(StringComparer.InvariantCulture);
public bool HasResources => _hasAccentColor || _colors.Count > 0;
public override bool HasResources => _hasAccentColor || _colors.Count > 0;
public bool TryGetResource(object key, ThemeVariant? theme, out object? value)
public override bool TryGetResource(object key, ThemeVariant? theme, out object? value)
{
if (key is string strKey)
{
@ -86,7 +86,7 @@ public partial class ColorPaletteResources : AvaloniaObject, IResourceNode
return default;
}
private void SetColor(string key, Color value)
{
if (value == default)
@ -113,6 +113,7 @@ public partial class ColorPaletteResources : AvaloniaObject, IResourceNode
_accentColorLight1, _accentColorLight2, _accentColorLight3) =
SystemAccentColors.CalculateAccentShades(_accentColor);
}
RaiseResourcesChanged();
}
}
}

Просмотреть файл

@ -1,20 +1,26 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Styling;
namespace Avalonia.Themes.Fluent;
internal class ColorPaletteResourcesCollection : AvaloniaDictionary<ThemeVariant, ColorPaletteResources>, IResourceProvider
internal sealed class ColorPaletteResourcesCollection : ResourceProvider, IDictionary<ThemeVariant, ColorPaletteResources>
{
public ColorPaletteResourcesCollection() : base(2)
private readonly AvaloniaDictionary<ThemeVariant, ColorPaletteResources> _inner;
public ColorPaletteResourcesCollection()
{
this.ForEachItem(
_inner = new AvaloniaDictionary<ThemeVariant, ColorPaletteResources>(2);
_inner.ForEachItem(
(key, x) =>
{
if (Owner is not null)
{
x.PropertyChanged += Palette_PropertyChanged;
((IResourceProvider)x).AddOwner(Owner);
}
if (key != ThemeVariant.Dark && key != ThemeVariant.Light)
@ -27,21 +33,21 @@ internal class ColorPaletteResourcesCollection : AvaloniaDictionary<ThemeVariant
{
if (Owner is not null)
{
x.PropertyChanged -= Palette_PropertyChanged;
((IResourceProvider)x).RemoveOwner(Owner);
}
},
() => throw new NotSupportedException("Dictionary reset not supported"));
}
public bool HasResources => Count > 0;
public bool TryGetResource(object key, ThemeVariant? theme, out object? value)
public override bool HasResources => _inner.Count > 0;
public override bool TryGetResource(object key, ThemeVariant? theme, out object? value)
{
if (theme == null || theme == ThemeVariant.Default)
{
theme = ThemeVariant.Light;
}
if (base.TryGetValue(theme, out var themePaletteResources)
if (_inner.TryGetValue(theme, out var themePaletteResources)
&& themePaletteResources.TryGetResource(key, theme, out value))
{
return true;
@ -51,25 +57,94 @@ internal class ColorPaletteResourcesCollection : AvaloniaDictionary<ThemeVariant
return false;
}
public IResourceHost? Owner { get; private set; }
public event EventHandler? OwnerChanged;
public void AddOwner(IResourceHost owner)
protected override void OnAddOwner(IResourceHost owner)
{
Owner = owner;
OwnerChanged?.Invoke(this, EventArgs.Empty);
}
public void RemoveOwner(IResourceHost owner)
{
Owner = null;
OwnerChanged?.Invoke(this, EventArgs.Empty);
}
private void Palette_PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == ColorPaletteResources.AccentProperty)
base.OnAddOwner(owner);
foreach (var palette in _inner.Values)
{
Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
((IResourceProvider)palette).AddOwner(owner);
}
}
protected override void OnRemoveOwner(IResourceHost owner)
{
base.OnRemoveOwner(owner);
foreach (var palette in _inner.Values)
{
((IResourceProvider)palette).RemoveOwner(owner);
}
}
IEnumerator<KeyValuePair<ThemeVariant, ColorPaletteResources>> IEnumerable<KeyValuePair<ThemeVariant, ColorPaletteResources>>.GetEnumerator()
{
return _inner.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_inner).GetEnumerator();
}
void ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>.Add(KeyValuePair<ThemeVariant, ColorPaletteResources> item)
{
((ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>)_inner).Add(item);
}
void ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>.Clear()
{
_inner.Clear();
}
bool ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>.Contains(KeyValuePair<ThemeVariant, ColorPaletteResources> item)
{
return ((ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>)_inner).Contains(item);
}
void ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>.CopyTo(KeyValuePair<ThemeVariant, ColorPaletteResources>[] array, int arrayIndex)
{
_inner.CopyTo(array, arrayIndex);
}
bool ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>.Remove(KeyValuePair<ThemeVariant, ColorPaletteResources> item)
{
return ((ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>)_inner).Remove(item);
}
int ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>.Count => _inner.Count;
bool ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>.IsReadOnly => _inner.IsReadOnly;
void IDictionary<ThemeVariant, ColorPaletteResources>.Add(ThemeVariant key, ColorPaletteResources value)
{
_inner.Add(key, value);
}
bool IDictionary<ThemeVariant, ColorPaletteResources>.ContainsKey(ThemeVariant key)
{
return _inner.ContainsKey(key);
}
bool IDictionary<ThemeVariant, ColorPaletteResources>.Remove(ThemeVariant key)
{
return _inner.Remove(key);
}
bool IDictionary<ThemeVariant, ColorPaletteResources>.TryGetValue(ThemeVariant key,
#if NET6_0_OR_GREATER
[MaybeNullWhen(false)]
#endif
out ColorPaletteResources value)
{
return _inner.TryGetValue(key, out value);
}
ColorPaletteResources IDictionary<ThemeVariant, ColorPaletteResources>.this[ThemeVariant key]
{
get => _inner[key];
set => _inner[key] = value;
}
ICollection<ThemeVariant> IDictionary<ThemeVariant, ColorPaletteResources>.Keys => _inner.Keys;
ICollection<ColorPaletteResources> IDictionary<ThemeVariant, ColorPaletteResources>.Values => _inner.Values;
}

Просмотреть файл

@ -54,7 +54,7 @@ namespace Avalonia.Themes.Fluent
get => _densityStyle;
set => SetAndRaise(DensityStyleProperty, ref _densityStyle, value);
}
public IDictionary<ThemeVariant, ColorPaletteResources> Palettes { get; }
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)

Просмотреть файл

@ -991,18 +991,11 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
}
}
public class TrackingResourceProvider : IResourceProvider
public class TrackingResourceProvider : ResourceProvider
{
public IResourceHost Owner { get; private set; }
public bool HasResources => true;
public override bool HasResources => true;
public List<object> RequestedResources { get; } = new List<object>();
public event EventHandler OwnerChanged { add { } remove { } }
public void AddOwner(IResourceHost owner) => Owner = owner;
public void RemoveOwner(IResourceHost owner) => Owner = null;
public bool TryGetResource(object key, ThemeVariant themeVariant, out object value)
public override bool TryGetResource(object key, ThemeVariant themeVariant, out object value)
{
RequestedResources.Add(key);
value = key;

Просмотреть файл

@ -127,25 +127,13 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
}
// See https://github.com/AvaloniaUI/Avalonia/issues/11172
public class LocaleCollection : IResourceProvider
public class LocaleCollection : ResourceProvider
{
private readonly Dictionary<object, IResourceProvider> _langs = new();
public override bool HasResources => true;
public IResourceHost? Owner { get; private set; }
public bool HasResources => true;
public event EventHandler? OwnerChanged
{
add { }
remove { }
}
public void AddOwner(IResourceHost owner) => Owner = owner;
public void RemoveOwner(IResourceHost owner) => Owner = null;
public bool TryGetResource(object key, ThemeVariant? theme, out object? value)
public override bool TryGetResource(object key, ThemeVariant? theme, out object? value)
{
if (_langs.TryGetValue("English", out var res))
{