From 48f48371dba67289e7a351810eab22e3f78f3a72 Mon Sep 17 00:00:00 2001 From: Stephane Delcroix Date: Thu, 2 May 2019 17:51:12 +0200 Subject: [PATCH] [X] pass the instance along the rlq (#6007) allow resourceprovider to track lifecycle of xaml-generated object --- Xamarin.Forms.Build.Tasks/XamlCTask.cs | 17 +++++++++++------ Xamarin.Forms.Core/Internals/ResourceLoader.cs | 1 + Xamarin.Forms.Xaml.UnitTests/ResourceLoader.xaml.cs | 13 +++++++++---- Xamarin.Forms.Xaml/XamlLoader.cs | 10 +++++++--- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/Xamarin.Forms.Build.Tasks/XamlCTask.cs b/Xamarin.Forms.Build.Tasks/XamlCTask.cs index 18bc53f..142e558 100644 --- a/Xamarin.Forms.Build.Tasks/XamlCTask.cs +++ b/Xamarin.Forms.Build.Tasks/XamlCTask.cs @@ -268,21 +268,26 @@ namespace Xamarin.Forms.Build.Tasks var nop = Instruction.Create(Nop); il.Emit(Newobj, module.ImportCtorReference(("Xamarin.Forms.Core", "Xamarin.Forms.Internals", "ResourceLoader/ResourceLoadingQuery"), 0)); - il.Emit(Dup); //dup the RLQ //AssemblyName + il.Emit(Dup); //dup the RLQ il.Emit(Ldtoken, module.ImportReference(initComp.DeclaringType)); il.Emit(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true)); il.Emit(Call, module.ImportMethodReference(("mscorlib", "System.Reflection", "IntrospectionExtensions"), methodName: "GetTypeInfo", parameterTypes: new[] { ("mscorlib", "System", "Type") }, isStatic: true)); il.Emit(Callvirt, module.ImportPropertyGetterReference(("mscorlib", "System.Reflection", "TypeInfo"), propertyName: "Assembly", flatten: true)); - il.Emit(Callvirt, module.ImportMethodReference(("mscorlib", "System.Reflection", "Assembly"), methodName: "GetName", parameterTypes: null)); //assemblyName - + il.Emit(Callvirt, module.ImportMethodReference(("mscorlib", "System.Reflection", "Assembly"), methodName: "GetName", parameterTypes: null)); il.Emit(Callvirt, module.ImportPropertySetterReference(("Xamarin.Forms.Core", "Xamarin.Forms.Internals", "ResourceLoader/ResourceLoadingQuery"), "AssemblyName")); - il.Emit(Dup); //dup the RLQ - il.Emit(Ldstr, resourcePath); //resourcePath + //ResourcePath + il.Emit(Dup); //dup the RLQ + il.Emit(Ldstr, resourcePath); il.Emit(Callvirt, module.ImportPropertySetterReference(("Xamarin.Forms.Core", "Xamarin.Forms.Internals", "ResourceLoader/ResourceLoadingQuery"), "ResourcePath")); - + + //Instance + il.Emit(Dup); //dup the RLQ + il.Emit(Ldarg_0); //Instance = this + il.Emit(Callvirt, module.ImportPropertySetterReference(("Xamarin.Forms.Core", "Xamarin.Forms.Internals", "ResourceLoader/ResourceLoadingQuery"), "Instance")); + il.Emit(Call, module.ImportMethodReference(("Xamarin.Forms.Core", "Xamarin.Forms.Internals", "ResourceLoader"), "CanProvideContentFor", 1, isStatic: true)); il.Emit(Brfalse, nop); il.Emit(Ldarg_0); diff --git a/Xamarin.Forms.Core/Internals/ResourceLoader.cs b/Xamarin.Forms.Core/Internals/ResourceLoader.cs index 8c7d476..a79e8d2 100644 --- a/Xamarin.Forms.Core/Internals/ResourceLoader.cs +++ b/Xamarin.Forms.Core/Internals/ResourceLoader.cs @@ -45,6 +45,7 @@ namespace Xamarin.Forms.Internals { public AssemblyName AssemblyName { get; set; } public string ResourcePath { get; set; } + public object Instance { get; set; } } public class ResourceLoadingResponse diff --git a/Xamarin.Forms.Xaml.UnitTests/ResourceLoader.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/ResourceLoader.xaml.cs index a00f821..4a5439c 100644 --- a/Xamarin.Forms.Xaml.UnitTests/ResourceLoader.xaml.cs +++ b/Xamarin.Forms.Xaml.UnitTests/ResourceLoader.xaml.cs @@ -63,10 +63,12 @@ namespace Xamarin.Forms.Xaml.UnitTests { var layout = new ResourceLoader(useCompiledXaml); Assert.That(layout.label.TextColor, Is.EqualTo(Color.FromHex("#368F95"))); - + object instance = null; Xamarin.Forms.Internals.ResourceLoader.ResourceProvider2 = (rlq) => { - if (rlq.ResourcePath == "ResourceLoader.xaml") - return new Forms.Internals.ResourceLoader.ResourceLoadingResponse { + if (rlq.ResourcePath == "ResourceLoader.xaml") { + instance = rlq.Instance; + return new Forms.Internals.ResourceLoader.ResourceLoadingResponse + { ResourceContent = @" "}; +" + }; + } return null; }; layout = new ResourceLoader(useCompiledXaml); + Assert.That(instance, Is.EqualTo(layout)); Assert.That(layout.label.TextColor, Is.EqualTo(Color.Pink)); } diff --git a/Xamarin.Forms.Xaml/XamlLoader.cs b/Xamarin.Forms.Xaml/XamlLoader.cs index 4cc769c..4d69764 100644 --- a/Xamarin.Forms.Xaml/XamlLoader.cs +++ b/Xamarin.Forms.Xaml/XamlLoader.cs @@ -63,7 +63,7 @@ namespace Xamarin.Forms.Xaml { public static void Load(object view, Type callingType) { - var xaml = GetXamlForType(callingType, out var useDesignProperties); + var xaml = GetXamlForType(callingType, view, out var useDesignProperties); if (string.IsNullOrEmpty(xaml)) throw new XamlParseException(string.Format("No embeddedresource found for {0}", callingType), new XmlLineInfo()); Load(view, xaml, useDesignProperties); @@ -151,7 +151,7 @@ namespace Xamarin.Forms.Xaml rootnode.Accept(new ApplyPropertiesVisitor(visitorContext, true), null); } - static string GetXamlForType(Type type, out bool useDesignProperties) + static string GetXamlForType(Type type, object instance, out bool useDesignProperties) { useDesignProperties = false; //the Previewer might want to provide it's own xaml for this... let them do that @@ -166,7 +166,11 @@ namespace Xamarin.Forms.Xaml var assembly = type.GetTypeInfo().Assembly; var resourceId = XamlResourceIdAttribute.GetResourceIdForType(type); - var rlr = ResourceLoader.ResourceProvider2?.Invoke(new ResourceLoader.ResourceLoadingQuery { AssemblyName = assembly.GetName(), ResourcePath = XamlResourceIdAttribute.GetPathForType(type) }); + var rlr = ResourceLoader.ResourceProvider2?.Invoke(new ResourceLoader.ResourceLoadingQuery { + AssemblyName = assembly.GetName(), + ResourcePath = XamlResourceIdAttribute.GetPathForType(type), + Instance = instance, + }); var alternateXaml = rlr?.ResourceContent; if (alternateXaml != null) { -- 2.7.4