From 6ed60610c9ddd823b523a0ccb485a2a31184d8a2 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Fri, 2 Dec 2022 00:53:45 -0500 Subject: [PATCH] Add ServiceProvider to the xaml runtime loader too --- .../AvaloniaXamlIlRuntimeCompiler.cs | 20 ++++++----- .../AvaloniaXamlLoader.cs | 7 ++-- .../RuntimeXamlLoaderDocument.cs | 7 +++- .../Avalonia.Markup.Xaml.UnitTests.csproj | 2 +- .../Xaml/StyleIncludeTests.cs | 35 ++++++++++--------- ...tor.xaml => StyleWithServiceProvider.xaml} | 2 +- ...ml.cs => StyleWithServiceProvider.xaml.cs} | 4 +-- .../Xaml/XamlIlTests.cs | 21 +++++++++++ 8 files changed, 64 insertions(+), 34 deletions(-) rename tests/Avalonia.Markup.Xaml.UnitTests/Xaml/{StyleWithServiceLocator.xaml => StyleWithServiceProvider.xaml} (60%) rename tests/Avalonia.Markup.Xaml.UnitTests/Xaml/{StyleWithServiceLocator.xaml.cs => StyleWithServiceProvider.xaml.cs} (70%) diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs index 1ee4402481..28d5a55f86 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs @@ -209,7 +209,7 @@ namespace Avalonia.Markup.Xaml.XamlIl }; var parsedDocuments = new List(); - var rootInstances = new List(); + var originalDocuments = new List(); foreach (var document in documents) { @@ -235,7 +235,7 @@ namespace Avalonia.Markup.Xaml.XamlIl builder, compiler.DefinePopulateMethod(builder, parsed, AvaloniaXamlIlCompiler.PopulateName, true), compiler.DefineBuildMethod(builder, parsed, AvaloniaXamlIlCompiler.BuildName, true))); - rootInstances.Add(document.RootInstance); + originalDocuments.Add(document); } compiler.TransformGroup(parsedDocuments); @@ -251,7 +251,9 @@ namespace Avalonia.Markup.Xaml.XamlIl indexerClosureType.CreateTypeInfo(); trampolineBuilder.CreateTypeInfo(); - return createdTypes.Zip(rootInstances, (l, r) => (l, r)).Select(t => LoadOrPopulate(t.Item1, t.Item2)).ToArray(); + return createdTypes.Zip(originalDocuments, (l, r) => (l, r)) + .Select(t => LoadOrPopulate(t.Item1, t.Item2.RootInstance, t.Item2.ServiceProvider)) + .ToArray(); } static object LoadSreCore(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration) @@ -260,7 +262,7 @@ namespace Avalonia.Markup.Xaml.XamlIl } #endif - static object LoadOrPopulate(Type created, object rootInstance) + static object LoadOrPopulate(Type created, object rootInstance, IServiceProvider parentServiceProvider) { var isp = Expression.Parameter(typeof(IServiceProvider)); @@ -271,6 +273,8 @@ namespace Avalonia.Markup.Xaml.XamlIl var populateCb = Expression.Lambda>( Expression.Call(populate, isp, Expression.Convert(epar, populate.GetParameters()[1].ParameterType)), isp, epar).Compile(); + + var serviceProvider = XamlIlRuntimeHelpers.CreateRootServiceProviderV3(parentServiceProvider); if (rootInstance == null) { @@ -282,7 +286,7 @@ namespace Avalonia.Markup.Xaml.XamlIl { overrideField.SetValue(null, new Action( - target => { populateCb(XamlIlRuntimeHelpers.CreateRootServiceProviderV2(), target); })); + target => { populateCb(serviceProvider, target); })); try { return Activator.CreateInstance(targetType); @@ -296,11 +300,11 @@ namespace Avalonia.Markup.Xaml.XamlIl var createCb = Expression.Lambda>( Expression.Convert(Expression.Call( created.GetMethod(AvaloniaXamlIlCompiler.BuildName), isp), typeof(object)), isp).Compile(); - return createCb(XamlIlRuntimeHelpers.CreateRootServiceProviderV2()); + return createCb(serviceProvider); } else { - populateCb(XamlIlRuntimeHelpers.CreateRootServiceProviderV2(), rootInstance); + populateCb(serviceProvider, rootInstance); return rootInstance; } } @@ -411,7 +415,7 @@ namespace Avalonia.Markup.Xaml.XamlIl var loaded = Assembly.LoadFile(asmPath) .GetTypes().First(x => x.Name == safeUri); _cecilGeneratedCache[safeUri] = loaded; - return LoadOrPopulate(loaded, rootInstance); + return LoadOrPopulate(loaded, rootInstance, null); } #endif } diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs index b5d222d979..ffacc69f91 100644 --- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs +++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs @@ -103,10 +103,9 @@ namespace Avalonia.Markup.Xaml var asset = assetLocator.OpenAndGetAssembly(uri, baseUri); using (var stream = asset.stream) { - return runtimeLoader.Load(new RuntimeXamlLoaderDocument(absoluteUri, stream), new RuntimeXamlLoaderConfiguration - { - LocalAssembly = asset.assembly - }); + var document = new RuntimeXamlLoaderDocument(absoluteUri, stream) { ServiceProvider = sp }; + var configuration = new RuntimeXamlLoaderConfiguration { LocalAssembly = asset.assembly }; + return runtimeLoader.Load(document, configuration); } } diff --git a/src/Markup/Avalonia.Markup.Xaml/RuntimeXamlLoaderDocument.cs b/src/Markup/Avalonia.Markup.Xaml/RuntimeXamlLoaderDocument.cs index be22888156..80335bbf53 100644 --- a/src/Markup/Avalonia.Markup.Xaml/RuntimeXamlLoaderDocument.cs +++ b/src/Markup/Avalonia.Markup.Xaml/RuntimeXamlLoaderDocument.cs @@ -66,5 +66,10 @@ public class RuntimeXamlLoaderDocument /// /// The stream containing the XAML. /// - public Stream XamlStream { get; set; } + public Stream XamlStream { get; } + + /// + /// Parent's service provider to pass to the Build method or type ctor, if available. + /// + public IServiceProvider? ServiceProvider { get; set; } } diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj b/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj index a9528edc91..6dce5eaab5 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj @@ -30,7 +30,7 @@ - + diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleIncludeTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleIncludeTests.cs index f148d95bf9..d76e51f419 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleIncludeTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleIncludeTests.cs @@ -279,33 +279,34 @@ public class StyleIncludeTests var sp = new TestServiceProvider(); var styleInclude = new StyleInclude(sp) { - Source = new Uri("avares://Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceLocator.xaml") + Source = new Uri("avares://Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceProvider.xaml") }; - var loaded = Assert.IsType(styleInclude.Loaded); + var loaded = Assert.IsType(styleInclude.Loaded); Assert.Equal( sp.GetService().Parents, loaded.ServiceProvider.GetService().Parents); } +} - private class TestServiceProvider : IServiceProvider, IUriContext, IAvaloniaXamlIlParentStackProvider +public class TestServiceProvider : IServiceProvider, IUriContext, IAvaloniaXamlIlParentStackProvider +{ + private IServiceProvider _root = XamlIlRuntimeHelpers.CreateRootServiceProviderV2(); + public object GetService(Type serviceType) { - private IServiceProvider _root = XamlIlRuntimeHelpers.CreateRootServiceProviderV2(); - public object GetService(Type serviceType) + if (serviceType == typeof(IUriContext)) { - if (serviceType == typeof(IUriContext)) - { - return this; - } - if (serviceType == typeof(IAvaloniaXamlIlParentStackProvider)) - { - return this; - } - return _root.GetService(serviceType); + return this; } - - public Uri BaseUri { get; set; } - public IEnumerable Parents { get; } = new[] { new ContentControl() }; + if (serviceType == typeof(IAvaloniaXamlIlParentStackProvider)) + { + return this; + } + return _root.GetService(serviceType); } + + public Uri BaseUri { get; set; } + public List Parents { get; set; } = new List { new ContentControl() }; + IEnumerable IAvaloniaXamlIlParentStackProvider.Parents => Parents; } diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceLocator.xaml b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceProvider.xaml similarity index 60% rename from tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceLocator.xaml rename to tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceProvider.xaml index 987c0f321a..664a26bae7 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceLocator.xaml +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceProvider.xaml @@ -1,5 +1,5 @@ diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceLocator.xaml.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceProvider.xaml.cs similarity index 70% rename from tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceLocator.xaml.cs rename to tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceProvider.xaml.cs index ceb122f05c..42da1604b9 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceLocator.xaml.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleWithServiceProvider.xaml.cs @@ -4,11 +4,11 @@ using Avalonia.Styling; namespace Avalonia.Markup.Xaml.UnitTests.Xaml; -public class StyleWithServiceLocator : Style +public class StyleWithServiceProvider : Style { public IServiceProvider ServiceProvider { get; } - public StyleWithServiceLocator(IServiceProvider sp = null) + public StyleWithServiceProvider(IServiceProvider sp = null) { ServiceProvider = sp; AvaloniaXamlLoader.Load(sp, this); diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs index 77a4932ccc..d945db0284 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs @@ -9,6 +9,7 @@ using Avalonia.Data.Converters; using Avalonia.Data.Core; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.Markup.Xaml.UnitTests.Xaml; using Avalonia.Media; using Avalonia.Styling; using Avalonia.Threading; @@ -314,6 +315,26 @@ namespace Avalonia.Markup.Xaml.UnitTests Assert.NotNull(parsed.ItemTemplate); } + + [Fact] + public void Runtime_Loader_Should_Pass_Parents_From_ServiceProvider() + { + var sp = new TestServiceProvider + { + Parents = new List + { + new UserControl { Resources = { ["Resource1"] = new SolidColorBrush(Colors.Blue) } } + } + }; + var document = new RuntimeXamlLoaderDocument(@" +