diff --git a/src/Avalonia.Base/Controls/IResourceDictionary.cs b/src/Avalonia.Base/Controls/IResourceDictionary.cs
index 2bd1f65638..6712498bf4 100644
--- a/src/Avalonia.Base/Controls/IResourceDictionary.cs
+++ b/src/Avalonia.Base/Controls/IResourceDictionary.cs
@@ -18,6 +18,6 @@ namespace Avalonia.Controls
///
/// Gets a collection of merged resource dictionaries that are specifically keyed and composed to address theme scenarios.
///
- IDictionary ThemeDictionaries { get; }
+ IDictionary ThemeDictionaries { get; }
}
}
diff --git a/src/Avalonia.Base/Controls/IThemeVariantProvider.cs b/src/Avalonia.Base/Controls/IThemeVariantProvider.cs
new file mode 100644
index 0000000000..d1dca2efbf
--- /dev/null
+++ b/src/Avalonia.Base/Controls/IThemeVariantProvider.cs
@@ -0,0 +1,22 @@
+using Avalonia.Metadata;
+using Avalonia.Styling;
+
+namespace Avalonia.Controls;
+
+///
+/// Resource provider with theme variant awareness.
+/// Can be used with .
+///
+///
+/// This is a helper interface for the XAML compiler to make Key property accessibly by the markup extensions.
+/// Which means, it can only be used with ResourceDictionaries and markup extensions in the XAML code.
+/// This API might be removed in the future minor updates.
+///
+[Unstable]
+public interface IThemeVariantProvider : IResourceProvider
+{
+ ///
+ /// Key property set by the compiler.
+ ///
+ ThemeVariant? Key { get; set; }
+}
diff --git a/src/Avalonia.Base/Controls/ResourceDictionary.cs b/src/Avalonia.Base/Controls/ResourceDictionary.cs
index 231a19baab..b928cf0672 100644
--- a/src/Avalonia.Base/Controls/ResourceDictionary.cs
+++ b/src/Avalonia.Base/Controls/ResourceDictionary.cs
@@ -13,13 +13,13 @@ namespace Avalonia.Controls
///
/// An indexed dictionary of resources.
///
- public class ResourceDictionary : IResourceDictionary
+ public class ResourceDictionary : IResourceDictionary, IThemeVariantProvider
{
private object? lastDeferredItemKey;
private Dictionary? _inner;
private IResourceHost? _owner;
private AvaloniaList? _mergedDictionaries;
- private AvaloniaDictionary? _themeDictionary;
+ private AvaloniaDictionary? _themeDictionary;
///
/// Initializes a new instance of the class.
@@ -93,13 +93,13 @@ namespace Avalonia.Controls
}
}
- public IDictionary ThemeDictionaries
+ public IDictionary ThemeDictionaries
{
get
{
if (_themeDictionary == null)
{
- _themeDictionary = new AvaloniaDictionary(2);
+ _themeDictionary = new AvaloniaDictionary(2);
_themeDictionary.ForEachItem(
(_, x) =>
{
@@ -120,6 +120,8 @@ namespace Avalonia.Controls
return _themeDictionary;
}
}
+
+ ThemeVariant? IThemeVariantProvider.Key { get; set; }
bool IResourceNode.HasResources
{
@@ -192,7 +194,7 @@ namespace Avalonia.Controls
if (_themeDictionary is not null)
{
- IResourceProvider? themeResourceProvider;
+ IThemeVariantProvider? themeResourceProvider;
if (theme is not null && theme != ThemeVariant.Default)
{
if (_themeDictionary.TryGetValue(theme, out themeResourceProvider)
diff --git a/src/Avalonia.Base/Controls/ResourceNodeExtensions.cs b/src/Avalonia.Base/Controls/ResourceNodeExtensions.cs
index 8aed1545a5..382ebac0e3 100644
--- a/src/Avalonia.Base/Controls/ResourceNodeExtensions.cs
+++ b/src/Avalonia.Base/Controls/ResourceNodeExtensions.cs
@@ -119,7 +119,19 @@ namespace Avalonia.Controls
resourceProvider = resourceProvider ?? throw new ArgumentNullException(nameof(resourceProvider));
key = key ?? throw new ArgumentNullException(nameof(key));
- return new FloatingResourceObservable(resourceProvider, key, converter);
+ return new FloatingResourceObservable(resourceProvider, key, null, converter);
+ }
+
+ public static IObservable GetResourceObservable(
+ this IResourceProvider resourceProvider,
+ object key,
+ ThemeVariant? defaultThemeVariant,
+ Func? converter = null)
+ {
+ resourceProvider = resourceProvider ?? throw new ArgumentNullException(nameof(resourceProvider));
+ key = key ?? throw new ArgumentNullException(nameof(key));
+
+ return new FloatingResourceObservable(resourceProvider, key, defaultThemeVariant, converter);
}
private class ResourceObservable : LightweightObservableBase
@@ -128,7 +140,10 @@ namespace Avalonia.Controls
private readonly object _key;
private readonly Func? _converter;
- public ResourceObservable(IResourceHost target, object key, Func? converter)
+ public ResourceObservable(
+ IResourceHost target,
+ object key,
+ Func? converter)
{
_target = target;
_key = key;
@@ -170,11 +185,8 @@ namespace Avalonia.Controls
private object? GetValue()
{
- if (_target is not IThemeVariantHost themeVariantHost
- || !_target.TryFindResource(_key, themeVariantHost.ActualThemeVariant, out var value))
- {
- value = _target.FindResource(_key) ?? AvaloniaProperty.UnsetValue;
- }
+ var theme = (_target as IThemeVariantHost)?.ActualThemeVariant;
+ var value = _target.FindResource(theme, _key) ?? AvaloniaProperty.UnsetValue;
return _converter?.Invoke(value) ?? value;
}
@@ -183,14 +195,20 @@ namespace Avalonia.Controls
private class FloatingResourceObservable : LightweightObservableBase
{
private readonly IResourceProvider _target;
+ private readonly ThemeVariant? _overrideThemeVariant;
private readonly object _key;
private readonly Func? _converter;
private IResourceHost? _owner;
- public FloatingResourceObservable(IResourceProvider target, object key, Func? converter)
+ public FloatingResourceObservable(
+ IResourceProvider target,
+ object key,
+ ThemeVariant? overrideThemeVariant,
+ Func? converter)
{
_target = target;
_key = key;
+ _overrideThemeVariant = overrideThemeVariant;
_converter = converter;
}
@@ -233,7 +251,7 @@ namespace Avalonia.Controls
{
_owner.ResourcesChanged -= ResourcesChanged;
}
- if (_owner is IThemeVariantHost themeVariantHost)
+ if (_overrideThemeVariant is null && _owner is IThemeVariantHost themeVariantHost)
{
themeVariantHost.ActualThemeVariantChanged += ActualThemeVariantChanged;
}
@@ -244,12 +262,11 @@ namespace Avalonia.Controls
{
_owner.ResourcesChanged += ResourcesChanged;
}
- if (_owner is IThemeVariantHost themeVariantHost2)
+ if (_overrideThemeVariant is null && _owner is IThemeVariantHost themeVariantHost2)
{
themeVariantHost2.ActualThemeVariantChanged -= ActualThemeVariantChanged;
}
-
PublishNext();
}
@@ -265,11 +282,8 @@ namespace Avalonia.Controls
private object? GetValue()
{
- if (!(_target.Owner is IThemeVariantHost themeVariantHost)
- || !_target.Owner.TryFindResource(_key, themeVariantHost.ActualThemeVariant, out var value))
- {
- value = _target.Owner?.FindResource(_key) ?? AvaloniaProperty.UnsetValue;
- }
+ var theme = _overrideThemeVariant ?? (_target.Owner as IThemeVariantHost)?.ActualThemeVariant;
+ var value = _target.Owner?.FindResource(theme, _key) ?? AvaloniaProperty.UnsetValue;
return _converter?.Invoke(value) ?? value;
}
diff --git a/src/Avalonia.Base/Styling/IThemeVariantHost.cs b/src/Avalonia.Base/Styling/IThemeVariantHost.cs
index 01583148a8..740887970b 100644
--- a/src/Avalonia.Base/Styling/IThemeVariantHost.cs
+++ b/src/Avalonia.Base/Styling/IThemeVariantHost.cs
@@ -7,7 +7,6 @@ namespace Avalonia.Styling;
///
/// Interface for the host element with a theme variant.
///
-[Unstable]
public interface IThemeVariantHost : IResourceHost
{
///
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
index 5ca2b09eba..23c67df810 100644
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
@@ -58,7 +58,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
new AvaloniaXamlIlSetterTransformer(),
new AvaloniaXamlIlConstructorServiceProviderTransformer(),
new AvaloniaXamlIlTransitionsTypeMetadataTransformer(),
- new AvaloniaXamlIlResolveByNameMarkupExtensionReplacer()
+ new AvaloniaXamlIlResolveByNameMarkupExtensionReplacer(),
+ new AvaloniaXamlIlThemeVariantProviderTransformer()
);
InsertBefore(
new AvaloniaXamlIlOptionMarkupExtensionTransformer());
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlThemeVariantProviderTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlThemeVariantProviderTransformer.cs
new file mode 100644
index 0000000000..05df8be1b6
--- /dev/null
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlThemeVariantProviderTransformer.cs
@@ -0,0 +1,31 @@
+using System.Linq;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Transform;
+using XamlX.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
+
+internal class AvaloniaXamlIlThemeVariantProviderTransformer : IXamlAstTransformer
+{
+ public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
+ {
+ var type = context.GetAvaloniaTypes().IThemeVariantProvider;
+ if (!(node is XamlAstObjectNode on
+ && type.IsAssignableFrom(on.Type.GetClrType())))
+ return node;
+
+ var keyDirective = on.Children.FirstOrDefault(n => n is XamlAstXmlDirective d
+ && d.Namespace == XamlNamespaces.Xaml2006 &&
+ d.Name == "Key") as XamlAstXmlDirective;
+ if (keyDirective is null)
+ return node;
+
+ var keyProp = type.Properties.First(p => p.Name == "Key");
+ on.Children.Add(new XamlAstXamlPropertyValueNode(keyDirective,
+ new XamlAstClrProperty(keyDirective, keyProp, context.Configuration),
+ keyDirective.Values, true));
+
+ return node;
+ }
+}
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
index 63683da0db..8ab84f4615 100644
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
@@ -110,6 +110,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlType IResourceDictionary { get; }
public IXamlType ResourceDictionary { get; }
public IXamlMethod ResourceDictionaryDeferredAdd { get; }
+ public IXamlType IThemeVariantProvider { get; }
public IXamlType UriKind { get; }
public IXamlConstructor UriConstructor { get; }
public IXamlType Style { get; }
@@ -250,6 +251,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
cfg.TypeSystem.GetType("System.Func`2").MakeGenericType(
cfg.TypeSystem.GetType("System.IServiceProvider"),
XamlIlTypes.Object));
+ IThemeVariantProvider = cfg.TypeSystem.GetType("Avalonia.Controls.IThemeVariantProvider");
UriKind = cfg.TypeSystem.GetType("System.UriKind");
UriConstructor = Uri.GetConstructor(new List() { cfg.WellKnownTypes.String, UriKind });
Style = cfg.TypeSystem.GetType("Avalonia.Styling.Style");
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
index e1b594e331..7f52c872ed 100644
--- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
@@ -3,6 +3,7 @@ using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Markup.Xaml.Converters;
using Avalonia.Media;
+using Avalonia.Styling;
namespace Avalonia.Markup.Xaml.MarkupExtensions
{
@@ -10,6 +11,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
{
private object? _anchor;
private BindingPriority _priority;
+ private ThemeVariant? _currentThemeVariant;
public DynamicResourceExtension()
{
@@ -36,6 +38,8 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
(object?)serviceProvider.GetFirstParent();
}
+ _currentThemeVariant = StaticResourceExtension.GetDictionaryVariant(serviceProvider);
+
return this;
}
@@ -59,7 +63,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
}
else if (_anchor is IResourceProvider resourceProvider)
{
- var source = resourceProvider.GetResourceObservable(ResourceKey, GetConverter(targetProperty));
+ var source = resourceProvider.GetResourceObservable(ResourceKey, _currentThemeVariant, GetConverter(targetProperty));
return InstancedBinding.OneWay(source, _priority);
}
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs
index 3de669b1e4..c23c31e24c 100644
--- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs
@@ -33,7 +33,8 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
var provideTarget = serviceProvider.GetService();
var targetObject = provideTarget?.TargetObject;
var targetProperty = provideTarget?.TargetProperty;
- var themeVariant = (targetObject as IThemeVariantHost)?.ActualThemeVariant;
+ var themeVariant = (targetObject as IThemeVariantHost)?.ActualThemeVariant
+ ?? GetDictionaryVariant(serviceProvider);
var targetType = targetProperty switch
{
@@ -78,6 +79,25 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
{
return ColorToBrushConverter.Convert(control.FindResource(ResourceKey!), targetType);
}
+
+ internal static ThemeVariant? GetDictionaryVariant(IServiceProvider serviceProvider)
+ {
+ var parents = serviceProvider.GetService()?.Parents;
+ if (parents is null)
+ {
+ return null;
+ }
+
+ foreach (var parent in parents)
+ {
+ if (parent is IThemeVariantProvider { Key: { } setKey })
+ {
+ return setKey;
+ }
+ }
+
+ return null;
+ }
}
}
diff --git a/src/Markup/Avalonia.Markup.Xaml/Styling/ResourceInclude.cs b/src/Markup/Avalonia.Markup.Xaml/Styling/ResourceInclude.cs
index fbcfdde565..eee02ea0d8 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Styling/ResourceInclude.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Styling/ResourceInclude.cs
@@ -13,7 +13,7 @@ namespace Avalonia.Markup.Xaml.Styling
/// When used in runtime, this type might be unsafe with trimming and AOT.
///
[RequiresUnreferencedCode(TrimmingMessages.StyleResourceIncludeRequiresUnreferenceCodeMessage)]
- public class ResourceInclude : IResourceProvider
+ public class ResourceInclude : IResourceProvider, IThemeVariantProvider
{
private readonly IServiceProvider? _serviceProvider;
private readonly Uri? _baseUri;
@@ -65,6 +65,8 @@ namespace Avalonia.Markup.Xaml.Styling
///
public Uri? Source { get; set; }
+ ThemeVariant? IThemeVariantProvider.Key { get; set; }
+
bool IResourceNode.HasResources => Loaded.HasResources;
public event EventHandler? OwnerChanged
diff --git a/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs b/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs
index e9b82d5381..8eadb3a3f0 100644
--- a/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs
+++ b/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs
@@ -1,7 +1,9 @@
using System;
+using System.Runtime.CompilerServices;
using Avalonia.Controls;
using Avalonia.Platform;
using Avalonia.Styling;
+using Avalonia.Threading;
using Avalonia.UnitTests;
using BenchmarkDotNet.Attributes;
using Moq;
@@ -30,27 +32,23 @@ namespace Avalonia.Benchmarks.Themes
_app.Dispose();
}
- [Benchmark]
- public void RepeatButton()
+ [Benchmark()]
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void CreateButton()
{
- var button = new RepeatButton();
+ var button = new Button();
_root.Child = button;
_root.LayoutManager.ExecuteLayoutPass();
+ Dispatcher.UIThread.RunJobs(DispatcherPriority.Loaded);
}
private static IDisposable CreateApp()
{
var services = new TestServices(
- assetLoader: new AssetLoader(),
- globalClock: new MockGlobalClock(),
- platform: new AppBuilder().RuntimePlatform,
- renderInterface: new MockPlatformRenderInterface(),
- standardCursorFactory: Mock.Of(),
- theme: () => LoadFluentTheme(),
+ renderInterface: new NullRenderingPlatform(),
dispatcherImpl: new NullThreadingPlatform(),
- fontManagerImpl: new MockFontManagerImpl(),
- textShaperImpl: new MockTextShaperImpl(),
- windowingPlatform: new MockWindowingPlatform());
+ standardCursorFactory: new NullCursorFactory(),
+ theme: () => LoadFluentTheme());
return UnitTestApplication.Start(services);
}
diff --git a/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs b/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs
index 7c0a3f8bdf..ac174e4bc2 100644
--- a/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs
+++ b/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs
@@ -1,5 +1,5 @@
using System;
-
+using System.Runtime.CompilerServices;
using Avalonia.Controls;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Platform;
@@ -29,6 +29,7 @@ namespace Avalonia.Benchmarks.Themes
}
[Benchmark]
+ [MethodImpl(MethodImplOptions.NoInlining)]
public bool InitFluentTheme()
{
UnitTestApplication.Current.Styles[0] = new FluentTheme();
@@ -36,6 +37,7 @@ namespace Avalonia.Benchmarks.Themes
}
[Benchmark]
+ [MethodImpl(MethodImplOptions.NoInlining)]
public bool InitSimpleTheme()
{
UnitTestApplication.Current.Styles[0] = new SimpleTheme();
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ThemeDictionariesTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ThemeDictionariesTests.cs
index 3ac4677694..2def84bb18 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ThemeDictionariesTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ThemeDictionariesTests.cs
@@ -1,9 +1,12 @@
-using System.Linq;
+using System;
+using System.Linq;
using Avalonia.Controls;
+using Avalonia.Controls.Documents;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Markup.Data;
using Avalonia.Markup.Xaml.MarkupExtensions;
+using Avalonia.Markup.Xaml.Templates;
using Avalonia.Media;
using Avalonia.Styling;
using Avalonia.UnitTests;
@@ -140,7 +143,7 @@ public class ThemeDictionariesTests : XamlTestBase
Assert.Equal(Colors.Black, ((ISolidColorBrush)border.Background)!.Color);
}
- [Fact(Skip = "Not implemented")]
+ [Fact]
public void StaticResource_Inside_Of_ThemeDictionaries_Should_Use_Same_Theme_Key()
{
var themeVariantScope = (ThemeVariantScope)AvaloniaRuntimeXamlLoader.Load(@"
@@ -183,6 +186,135 @@ public class ThemeDictionariesTests : XamlTestBase
Assert.Equal(Colors.Black, ((ISolidColorBrush)border.Background)!.Color);
}
+
+ [Fact]
+ public void StaticResource_Inside_Of_ThemeDictionaries_Should_Use_Same_Theme_Key_From_Inner_File()
+ {
+ var documents = new[]
+ {
+ new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Inner.xaml"), @"
+
+
+ "),
+ new RuntimeXamlLoaderDocument(@"
+
+
+
+ Green
+
+
+
+
+
+ White
+
+
+
+
+
+ ")
+ };
+
+ var parsed = AvaloniaRuntimeXamlLoader.LoadGroup(documents);
+ var dictionary = (ResourceDictionary)parsed[1]!;
+
+ dictionary.TryGetResource("InnerKey", ThemeVariant.Dark, out var resource);
+ var colorResource = Assert.IsType(resource);
+ Assert.Equal(Colors.White, colorResource);
+
+ dictionary.TryGetResource("InnerKey", ThemeVariant.Light, out resource);
+ colorResource = Assert.IsType(resource);
+ Assert.Equal(Colors.Green, colorResource);
+ }
+
+ [Fact]
+ public void DynamicResource_Inside_Of_ThemeDictionaries_Should_Use_Same_Theme_Key_From_Inner_File()
+ {
+ var documents = new[]
+ {
+ new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Inner.xaml"), @"
+
+
+ "),
+ new RuntimeXamlLoaderDocument(@"
+
+
+
+ Green
+
+
+
+
+
+ White
+
+
+
+
+
+ ")
+ };
+
+ var parsed = AvaloniaRuntimeXamlLoader.LoadGroup(documents);
+ var dictionary1 = (ResourceDictionary)parsed[0]!;
+ var dictionary2 = (ResourceDictionary)parsed[1]!;
+ var ownerApp = new Application(); // DynamicResource needs an owner to work
+ ownerApp.RequestedThemeVariant = new ThemeVariant("FakeOne", null);
+ ownerApp.Resources.MergedDictionaries.Add(dictionary1);
+ ownerApp.Resources.MergedDictionaries.Add(dictionary2);
+
+ dictionary2.TryGetResource("InnerKey", ThemeVariant.Dark, out var resource);
+ var colorResource = Assert.IsAssignableFrom(resource);
+ Assert.Equal(Colors.White, colorResource.Color);
+
+ dictionary2.TryGetResource("InnerKey", ThemeVariant.Light, out resource);
+ colorResource = Assert.IsAssignableFrom(resource);
+ Assert.Equal(Colors.Green, colorResource.Color);
+ }
+
+ [Fact]
+ public void DynamicResource_Inside_Control_Inside_Of_ThemeDictionaries_Should_Use_Control_Theme_Variant()
+ {
+ var documents = new[]
+ {
+ new RuntimeXamlLoaderDocument(@"
+
+
+
+ Green
+
+
+
+
+
+ White
+
+
+
+
+
+ ")
+ };
+
+ var parsed = AvaloniaRuntimeXamlLoader.LoadGroup(documents);
+ var dictionary = (ResourceDictionary)parsed[0]!;
+
+ dictionary.TryGetResource("Template", ThemeVariant.Dark, out var resource);
+ var control = Assert.IsType((resource as Template)?.Build());
+ control.Resources.MergedDictionaries.Add(dictionary);
+ Assert.Equal(Colors.Green, ((ISolidColorBrush)control[TextElement.ForegroundProperty]!).Color);
+ control.Resources.MergedDictionaries.Remove(dictionary);
+
+ dictionary.TryGetResource("Template", ThemeVariant.Light, out resource);
+ control = Assert.IsType((resource as Template)?.Build());
+ control.Resources.MergedDictionaries.Add(dictionary);
+ Assert.Equal(Colors.White, ((ISolidColorBrush)control[TextElement.ForegroundProperty]!).Color);
+ }
[Fact]
public void StaticResource_Outside_Of_Dictionaries_Should_Use_Control_ThemeVariant()