diff options
15 files changed, 137 insertions, 33 deletions
diff --git a/Xamarin.Forms.Build.Tasks/XamlCTask.cs b/Xamarin.Forms.Build.Tasks/XamlCTask.cs index c41ddd97..8bbb0b26 100644 --- a/Xamarin.Forms.Build.Tasks/XamlCTask.cs +++ b/Xamarin.Forms.Build.Tasks/XamlCTask.cs @@ -176,7 +176,7 @@ namespace Xamarin.Forms.Build.Tasks Logger.LogString(2, " Replacing {0}.InitializeComponent ()... ", typeDef.Name); Exception e; - if (!TryCoreCompile(initComp, initCompRuntime, rootnode, out e)) { + if (!TryCoreCompile(initComp, initCompRuntime, rootnode, resource.Name, out e)) { success = false; Logger.LogLine(2, "failed."); (thrownExceptions = thrownExceptions ?? new List<Exception>()).Add(e); @@ -195,6 +195,8 @@ namespace Xamarin.Forms.Build.Tasks Logger.LogLine(2, "done"); } + Logger.LogLine(2, ""); + if (outputGeneratedILAsCode) Logger.LogLine(2, " Decompiling option has been removed. Use a 3rd party decompiler to admire the beauty of the IL generated"); @@ -238,45 +240,59 @@ namespace Xamarin.Forms.Build.Tasks return success; } - bool TryCoreCompile(MethodDefinition initComp, MethodDefinition initCompRuntime, ILRootNode rootnode, out Exception exception) + bool TryCoreCompile(MethodDefinition initComp, MethodDefinition initCompRuntime, ILRootNode rootnode, string resourceId, out Exception exception) { try { var body = new MethodBody(initComp); + var module = body.Method.Module; var il = body.GetILProcessor(); il.Emit(OpCodes.Nop); if (initCompRuntime != null) { // Generating branching code for the Previewer - // IL_0007: call class [mscorlib]System.Func`2<class [mscorlib]System.Type,string> class [Xamarin.Forms.Xaml.Internals]Xamarin.Forms.Xaml.XamlLoader::get_XamlFileProvider() - // IL_000c: brfalse IL_0031 - // IL_0011: call class [mscorlib]System.Func`2<class [mscorlib]System.Type,string> class [Xamarin.Forms.Xaml.Internals]Xamarin.Forms.Xaml.XamlLoader::get_XamlFileProvider() - // IL_0016: ldarg.0 - // IL_0017: call instance class [mscorlib]System.Type object::GetType() - // IL_001c: callvirt instance !1 class [mscorlib]System.Func`2<class [mscorlib]System.Type, string>::Invoke(!0) - // IL_0021: brfalse IL_0031 - // IL_0026: ldarg.0 - // IL_0027: call instance void class Xamarin.Forms.Xaml.UnitTests.XamlLoaderGetXamlForTypeTests::__InitComponentRuntime() - // IL_002c: ret - // IL_0031: nop + //First using the ResourceLoader var nop = Instruction.Create(OpCodes.Nop); + var getResourceProvider = module.ImportReference(module.ImportReference(typeof(Internals.ResourceLoader)) + .Resolve() + .Properties.FirstOrDefault(pd => pd.Name == "ResourceProvider") + .GetMethod); + il.Emit(OpCodes.Call, getResourceProvider); + il.Emit(OpCodes.Brfalse, nop); + il.Emit(OpCodes.Call, getResourceProvider); + il.Emit(OpCodes.Ldstr, resourceId); + var func = module.ImportReference(module.ImportReference(typeof(Func<string, string>)) + .Resolve() + .Methods.FirstOrDefault(md => md.Name == "Invoke")); + func = func.ResolveGenericParameters(module.ImportReference(typeof(Func<string, string>)), module); + il.Emit(OpCodes.Callvirt, func); + il.Emit(OpCodes.Brfalse, nop); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, initCompRuntime); + il.Emit(OpCodes.Ret); + il.Append(nop); - var getXamlFileProvider = body.Method.Module.ImportReference(body.Method.Module.ImportReference(typeof(Xamarin.Forms.Xaml.Internals.XamlLoader)) + //Or using the deprecated XamlLoader + nop = Instruction.Create(OpCodes.Nop); +#pragma warning disable 0618 + var getXamlFileProvider = module.ImportReference(module.ImportReference(typeof(Xaml.Internals.XamlLoader)) .Resolve() .Properties.FirstOrDefault(pd => pd.Name == "XamlFileProvider") .GetMethod); +#pragma warning restore 0618 + il.Emit(OpCodes.Call, getXamlFileProvider); il.Emit(OpCodes.Brfalse, nop); il.Emit(OpCodes.Call, getXamlFileProvider); il.Emit(OpCodes.Ldarg_0); - var getType = body.Method.Module.ImportReference(body.Method.Module.ImportReference(typeof(object)) + var getType = module.ImportReference(module.ImportReference(typeof(object)) .Resolve() .Methods.FirstOrDefault(md => md.Name == "GetType")); il.Emit(OpCodes.Call, getType); - var func = body.Method.Module.ImportReference(body.Method.Module.ImportReference(typeof(Func<Type, string>)) + func = module.ImportReference(module.ImportReference(typeof(Func<Type, string>)) .Resolve() .Methods.FirstOrDefault(md => md.Name == "Invoke")); - func = func.ResolveGenericParameters(body.Method.Module.ImportReference(typeof(Func<Type, string>)), body.Method.Module); + func = func.ResolveGenericParameters(module.ImportReference(typeof(Func<Type, string>)), module); il.Emit(OpCodes.Callvirt, func); il.Emit(OpCodes.Brfalse, nop); il.Emit(OpCodes.Ldarg_0); @@ -285,7 +301,7 @@ namespace Xamarin.Forms.Build.Tasks il.Append(nop); } - var visitorContext = new ILContext(il, body, body.Method.Module); + var visitorContext = new ILContext(il, body, module); rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null); rootnode.Accept(new ExpandMarkupsVisitor(visitorContext), null); diff --git a/Xamarin.Forms.Core/Internals/ResourceLoader.cs b/Xamarin.Forms.Core/Internals/ResourceLoader.cs new file mode 100644 index 00000000..e7b1be1d --- /dev/null +++ b/Xamarin.Forms.Core/Internals/ResourceLoader.cs @@ -0,0 +1,9 @@ +using System; +namespace Xamarin.Forms.Internals +{ + public static class ResourceLoader + { + public static Func<string, string> ResourceProvider { get; internal set; } + internal static Action<Exception> ExceptionHandler { get; set; } + } +}
\ No newline at end of file diff --git a/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj b/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj index 5e001cdc..a052352e 100644 --- a/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj +++ b/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj @@ -458,6 +458,7 @@ <Compile Include="PlatformConfiguration\AndroidSpecific\ListView.cs" /> <Compile Include="ITextElement.cs" /> <Compile Include="TextElement.cs" /> + <Compile Include="Internals\ResourceLoader.cs" /> </ItemGroup> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" /> <ItemGroup> @@ -473,4 +474,4 @@ </PropertyGroup> <ItemGroup /> <ItemGroup /> -</Project>
\ No newline at end of file +</Project> diff --git a/Xamarin.Forms.Xaml.UnitTests/DefaultCtorRouting2.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/DefaultCtorRouting2.xaml.cs index 05254770..faa9fedc 100644 --- a/Xamarin.Forms.Xaml.UnitTests/DefaultCtorRouting2.xaml.cs +++ b/Xamarin.Forms.Xaml.UnitTests/DefaultCtorRouting2.xaml.cs @@ -26,7 +26,10 @@ namespace Xamarin.Forms.Xaml.UnitTests public void TearDown() { Device.PlatformServices = null; +#pragma warning disable 0618 Internals.XamlLoader.XamlFileProvider = null; +#pragma warning restore 0618 + } [Test] @@ -39,7 +42,9 @@ namespace Xamarin.Forms.Xaml.UnitTests [Test] public void ShouldntBeCompiled() { +#pragma warning disable 0618 Internals.XamlLoader.XamlFileProvider = (t) => { +#pragma warning restore 0618 if (t == typeof(DefaultCtorRouting2)) return @"<?xml version=""1.0"" encoding=""UTF-8""?> <ContentPage xmlns=""http://xamarin.com/schemas/2014/forms"" diff --git a/Xamarin.Forms.Xaml.UnitTests/XamlLoaderGetXamlForTypeTests.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/XamlLoaderGetXamlForTypeTests.xaml.cs index 10c3f2e2..dcffb3c5 100644 --- a/Xamarin.Forms.Xaml.UnitTests/XamlLoaderGetXamlForTypeTests.xaml.cs +++ b/Xamarin.Forms.Xaml.UnitTests/XamlLoaderGetXamlForTypeTests.xaml.cs @@ -25,7 +25,10 @@ namespace Xamarin.Forms.Xaml.UnitTests [SetUp] public void SetUp() { +#pragma warning disable 0618 Xamarin.Forms.Xaml.Internals.XamlLoader.XamlFileProvider = null; +#pragma warning restore 0618 + } [TestCase(false)] @@ -35,7 +38,9 @@ namespace Xamarin.Forms.Xaml.UnitTests var layout = new XamlLoaderGetXamlForTypeTests(useCompiledXaml); Assert.That(layout.Content, Is.TypeOf<Button>()); +#pragma warning disable 0618 Xamarin.Forms.Xaml.Internals.XamlLoader.XamlFileProvider = (t) => { +#pragma warning restore 0618 if (t == typeof(XamlLoaderGetXamlForTypeTests)) return @" <ContentPage xmlns=""http://xamarin.com/schemas/2014/forms"" diff --git a/Xamarin.Forms.Xaml.Xamlc/Xamarin.Forms.Xaml.Xamlc.csproj b/Xamarin.Forms.Xaml.Xamlc/Xamarin.Forms.Xaml.Xamlc.csproj index 4430103b..093e18da 100644 --- a/Xamarin.Forms.Xaml.Xamlc/Xamarin.Forms.Xaml.Xamlc.csproj +++ b/Xamarin.Forms.Xaml.Xamlc/Xamarin.Forms.Xaml.Xamlc.csproj @@ -42,6 +42,18 @@ <Reference Include="System" /> <Reference Include="Microsoft.Build.Utilities.v4.0" /> <Reference Include="Microsoft.Build.Framework" /> + <Reference Include="Mono.Cecil"> + <HintPath>..\packages\Mono.Cecil.0.10.0-beta4\lib\net40\Mono.Cecil.dll</HintPath> + </Reference> + <Reference Include="Mono.Cecil.Mdb"> + <HintPath>..\packages\Mono.Cecil.0.10.0-beta4\lib\net40\Mono.Cecil.Mdb.dll</HintPath> + </Reference> + <Reference Include="Mono.Cecil.Pdb"> + <HintPath>..\packages\Mono.Cecil.0.10.0-beta4\lib\net40\Mono.Cecil.Pdb.dll</HintPath> + </Reference> + <Reference Include="Mono.Cecil.Rocks"> + <HintPath>..\packages\Mono.Cecil.0.10.0-beta4\lib\net40\Mono.Cecil.Rocks.dll</HintPath> + </Reference> </ItemGroup> <ItemGroup> <Compile Include="..\Xamarin.Forms.Xaml.Xamlg\Mono.Options\Options.cs"> @@ -59,4 +71,7 @@ <Name>Xamarin.Forms.Build.Tasks</Name> </ProjectReference> </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> </Project> diff --git a/Xamarin.Forms.Xaml.Xamlc/packages.config b/Xamarin.Forms.Xaml.Xamlc/packages.config new file mode 100644 index 00000000..809273bc --- /dev/null +++ b/Xamarin.Forms.Xaml.Xamlc/packages.config @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Mono.Cecil" version="0.10.0-beta4" targetFramework="net451" /> +</packages>
\ No newline at end of file diff --git a/Xamarin.Forms.Xaml/ApplyPropertiesVisitor.cs b/Xamarin.Forms.Xaml/ApplyPropertiesVisitor.cs index 5b8a8403..337b2ace 100644 --- a/Xamarin.Forms.Xaml/ApplyPropertiesVisitor.cs +++ b/Xamarin.Forms.Xaml/ApplyPropertiesVisitor.cs @@ -305,8 +305,8 @@ namespace Xamarin.Forms.Xaml return; xpe = xpe ?? new XamlParseException($"Cannot assign property \"{localName}\": Property does not exists, or is not assignable, or mismatching type between value and property", lineInfo); - if (context.DoNotThrowOnExceptions) - System.Diagnostics.Debug.WriteLine(xpe.Message); + if (context.ExceptionHandler != null) + context.ExceptionHandler(xpe); else throw xpe; } diff --git a/Xamarin.Forms.Xaml/HydratationContext.cs b/Xamarin.Forms.Xaml/HydratationContext.cs index 7273a2cc..172bce17 100644 --- a/Xamarin.Forms.Xaml/HydratationContext.cs +++ b/Xamarin.Forms.Xaml/HydratationContext.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace Xamarin.Forms.Xaml { - internal class HydratationContext + class HydratationContext { public HydratationContext() { @@ -17,8 +17,8 @@ namespace Xamarin.Forms.Xaml public HydratationContext ParentContext { get; set; } - public bool DoNotThrowOnExceptions { get; set; } + public Action<Exception> ExceptionHandler { get; set; } public object RootElement { get; set; } } -} +}
\ No newline at end of file diff --git a/Xamarin.Forms.Xaml/XamlFilePathAttribute.cs b/Xamarin.Forms.Xaml/XamlFilePathAttribute.cs index 615f290b..7a6d665b 100644 --- a/Xamarin.Forms.Xaml/XamlFilePathAttribute.cs +++ b/Xamarin.Forms.Xaml/XamlFilePathAttribute.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; namespace Xamarin.Forms.Xaml { - [AttributeUsage(AttributeTargets.Class, Inherited = false)] + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] public sealed class XamlFilePathAttribute : Attribute { public XamlFilePathAttribute([CallerFilePath] string filePath = "") diff --git a/Xamarin.Forms.Xaml/XamlLoader.cs b/Xamarin.Forms.Xaml/XamlLoader.cs index 7fee40da..cdf73bdd 100644 --- a/Xamarin.Forms.Xaml/XamlLoader.cs +++ b/Xamarin.Forms.Xaml/XamlLoader.cs @@ -32,9 +32,11 @@ using System.IO; using System.Reflection; using System.Text.RegularExpressions; using System.Xml; +using Xamarin.Forms.Internals; namespace Xamarin.Forms.Xaml.Internals { + [Obsolete ("Replaced by ResourceLoader")] public static class XamlLoader { public static Func<Type, string> XamlFileProvider { get; internal set; } @@ -44,7 +46,7 @@ namespace Xamarin.Forms.Xaml.Internals namespace Xamarin.Forms.Xaml { - internal static class XamlLoader + static class XamlLoader { static readonly Dictionary<Type, string> XamlResources = new Dictionary<Type, string>(); @@ -75,7 +77,9 @@ namespace Xamarin.Forms.Xaml XamlParser.ParseXaml (rootnode, reader); Visit (rootnode, new HydratationContext { RootElement = view, - DoNotThrowOnExceptions = Xamarin.Forms.Xaml.Internals.XamlLoader.DoNotThrowOnExceptions +#pragma warning disable 0618 + ExceptionHandler = ResourceLoader.ExceptionHandler ?? (Internals.XamlLoader.DoNotThrowOnExceptions ? e => { }: (Action<Exception>)null) +#pragma warning restore 0618 }); break; } @@ -99,7 +103,7 @@ namespace Xamarin.Forms.Xaml var rootnode = new RuntimeRootNode (new XmlType (reader.NamespaceURI, reader.Name, null), null, (IXmlNamespaceResolver)reader); XamlParser.ParseXaml (rootnode, reader); var visitorContext = new HydratationContext { - DoNotThrowOnExceptions = doNotThrow, + ExceptionHandler = doNotThrow ? e => { } : (Action<Exception>)null, }; var cvv = new CreateValuesVisitor (visitorContext); cvv.Visit ((ElementNode)rootnode, null); @@ -127,10 +131,14 @@ namespace Xamarin.Forms.Xaml static string GetXamlForType(Type type) { - string xaml = null; - //the Previewer might want to provide it's own xaml for this... let them do that - if (Xamarin.Forms.Xaml.Internals.XamlLoader.XamlFileProvider != null && (xaml = Xamarin.Forms.Xaml.Internals.XamlLoader.XamlFileProvider(type)) != null) + //the check at the end is preferred (using ResourceLoader). keep this until all the previewers are updated + +#pragma warning disable 0618 + var xaml = Internals.XamlLoader.XamlFileProvider?.Invoke(type); +#pragma warning restore 0618 + + if (xaml != null && ResourceLoader.ResourceProvider == null) return xaml; var assembly = type.GetTypeInfo().Assembly; @@ -189,7 +197,8 @@ namespace Xamarin.Forms.Xaml return null; XamlResources[type] = resourceName; - return xaml; + var alternateXaml = ResourceLoader.ResourceProvider?.Invoke(resourceName); + return alternateXaml ?? xaml; } static bool ResourceMatchesFilename(Assembly assembly, string resource, string filename) diff --git a/docs/Xamarin.Forms.Core/Xamarin.Forms.Internals/ResourceLoader.xml b/docs/Xamarin.Forms.Core/Xamarin.Forms.Internals/ResourceLoader.xml new file mode 100644 index 00000000..58450ad3 --- /dev/null +++ b/docs/Xamarin.Forms.Core/Xamarin.Forms.Internals/ResourceLoader.xml @@ -0,0 +1,34 @@ +<Type Name="ResourceLoader" FullName="Xamarin.Forms.Internals.ResourceLoader"> + <TypeSignature Language="C#" Value="public static class ResourceLoader" /> + <TypeSignature Language="ILAsm" Value=".class public auto ansi abstract sealed beforefieldinit ResourceLoader extends System.Object" /> + <AssemblyInfo> + <AssemblyName>Xamarin.Forms.Core</AssemblyName> + <AssemblyVersion>2.0.0.0</AssemblyVersion> + </AssemblyInfo> + <Base> + <BaseTypeName>System.Object</BaseTypeName> + </Base> + <Interfaces /> + <Docs> + <summary>To be added.</summary> + <remarks>To be added.</remarks> + </Docs> + <Members> + <Member MemberName="ResourceProvider"> + <MemberSignature Language="C#" Value="public static Func<string,string> ResourceProvider { get; }" /> + <MemberSignature Language="ILAsm" Value=".property class System.Func`2<string, string> ResourceProvider" /> + <MemberType>Property</MemberType> + <AssemblyInfo> + <AssemblyVersion>2.0.0.0</AssemblyVersion> + </AssemblyInfo> + <ReturnValue> + <ReturnType>System.Func<System.String,System.String></ReturnType> + </ReturnValue> + <Docs> + <summary>To be added.</summary> + <value>To be added.</value> + <remarks>To be added.</remarks> + </Docs> + </Member> + </Members> +</Type> diff --git a/docs/Xamarin.Forms.Core/index.xml b/docs/Xamarin.Forms.Core/index.xml index 32d7fe8a..4d37119d 100644 --- a/docs/Xamarin.Forms.Core/index.xml +++ b/docs/Xamarin.Forms.Core/index.xml @@ -478,6 +478,7 @@ <Type Name="ReflectionExtensions" Kind="Class" /> <Type Name="Registrar" Kind="Class" /> <Type Name="Registrar`1" DisplayName="Registrar<TRegistrable>" Kind="Class" /> + <Type Name="ResourceLoader" Kind="Class" /> <Type Name="ResourcesChangedEventArgs" Kind="Class" /> <Type Name="SetValueFlags" Kind="Enumeration" /> <Type Name="TableModel" Kind="Class" /> diff --git a/docs/Xamarin.Forms.Xaml/Xamarin.Forms.Xaml.Internals/XamlLoader.xml b/docs/Xamarin.Forms.Xaml/Xamarin.Forms.Xaml.Internals/XamlLoader.xml index 8c7c8cff..405f2cdd 100644 --- a/docs/Xamarin.Forms.Xaml/Xamarin.Forms.Xaml.Internals/XamlLoader.xml +++ b/docs/Xamarin.Forms.Xaml/Xamarin.Forms.Xaml.Internals/XamlLoader.xml @@ -9,6 +9,11 @@ <BaseTypeName>System.Object</BaseTypeName> </Base> <Interfaces /> + <Attributes> + <Attribute> + <AttributeName>System.Obsolete("Replaced by ResourceLoader")</AttributeName> + </Attribute> + </Attributes> <Docs> <summary>For internal use by the XAML platform.</summary> <remarks>To be added.</remarks> diff --git a/docs/Xamarin.Forms.Xaml/Xamarin.Forms.Xaml/XamlFilePathAttribute.xml b/docs/Xamarin.Forms.Xaml/Xamarin.Forms.Xaml/XamlFilePathAttribute.xml index c0027df4..ec83ddc6 100644 --- a/docs/Xamarin.Forms.Xaml/Xamarin.Forms.Xaml/XamlFilePathAttribute.xml +++ b/docs/Xamarin.Forms.Xaml/Xamarin.Forms.Xaml/XamlFilePathAttribute.xml @@ -11,7 +11,7 @@ <Interfaces /> <Attributes> <Attribute> - <AttributeName>System.AttributeUsage(System.AttributeTargets.Class, Inherited=false)</AttributeName> + <AttributeName>System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple=false, Inherited=false)</AttributeName> </Attribute> </Attributes> <Docs> |