summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Build.Tasks
diff options
context:
space:
mode:
authorStephane Delcroix <stephane@delcroix.org>2016-09-26 22:29:47 +0200
committerJason Smith <jason.smith@xamarin.com>2016-09-26 13:29:47 -0700
commit55f066584c507ec92d5054fac4f3a35f54c05522 (patch)
tree358ec7ed9a74e008b3bc601a9b391bcd193fb86b /Xamarin.Forms.Build.Tasks
parente6a20ddedb6c8dee989b4ac19c6e83cecafe9f29 (diff)
downloadxamarin-forms-55f066584c507ec92d5054fac4f3a35f54c05522.tar.gz
xamarin-forms-55f066584c507ec92d5054fac4f3a35f54c05522.tar.bz2
xamarin-forms-55f066584c507ec92d5054fac4f3a35f54c05522.zip
[XamlC] Compiled converters (#358)
Diffstat (limited to 'Xamarin.Forms.Build.Tasks')
-rw-r--r--Xamarin.Forms.Build.Tasks/CompiledConverters/BindablePropertyConverter.cs84
-rw-r--r--Xamarin.Forms.Build.Tasks/CompiledConverters/BindingTypeConverter.cs32
-rw-r--r--Xamarin.Forms.Build.Tasks/CompiledConverters/BoundsTypeConverter.cs73
-rw-r--r--Xamarin.Forms.Build.Tasks/CompiledConverters/ColorTypeConverter.cs55
-rw-r--r--Xamarin.Forms.Build.Tasks/CompiledConverters/ICompiledTypeConverter.cs12
-rw-r--r--Xamarin.Forms.Build.Tasks/CompiledConverters/LayoutOptionsConverter.cs37
-rw-r--r--Xamarin.Forms.Build.Tasks/CompiledConverters/RectangleTypeConverter.cs49
-rw-r--r--Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs15
-rw-r--r--Xamarin.Forms.Build.Tasks/ExpandMarkupsVisitor.cs2
-rw-r--r--Xamarin.Forms.Build.Tasks/NodeILExtensions.cs15
-rw-r--r--Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs14
-rw-r--r--Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj10
-rw-r--r--Xamarin.Forms.Build.Tasks/XmlTypeExtensions.cs5
13 files changed, 394 insertions, 9 deletions
diff --git a/Xamarin.Forms.Build.Tasks/CompiledConverters/BindablePropertyConverter.cs b/Xamarin.Forms.Build.Tasks/CompiledConverters/BindablePropertyConverter.cs
new file mode 100644
index 00000000..92a53539
--- /dev/null
+++ b/Xamarin.Forms.Build.Tasks/CompiledConverters/BindablePropertyConverter.cs
@@ -0,0 +1,84 @@
+using System.Collections.Generic;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Xamarin.Forms.Build.Tasks;
+using Xamarin.Forms.Xaml;
+
+using static System.String;
+
+namespace Xamarin.Forms.Core.XamlC
+{
+ class BindablePropertyConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ModuleDefinition module, BaseNode node)
+ {
+ if (IsNullOrEmpty(value)) {
+ yield return Instruction.Create(OpCodes.Ldnull);
+ yield break;
+ }
+
+ FieldReference bpRef = null;
+ string typeName = null, propertyName = null;
+
+ var parts = value.Split('.');
+ if (parts.Length == 1) {
+ var parent = node.Parent?.Parent as IElementNode;
+ if ((node.Parent as ElementNode)?.XmlType.NamespaceUri == "http://xamarin.com/schemas/2014/forms" && (node.Parent as ElementNode)?.XmlType.Name == "Setter") {
+ if (parent.XmlType.NamespaceUri == "http://xamarin.com/schemas/2014/forms" &&
+ (parent.XmlType.Name == "Trigger" || parent.XmlType.Name == "DataTrigger" || parent.XmlType.Name == "MultiTrigger" || parent.XmlType.Name == "Style")) {
+ var ttnode = (parent as ElementNode).Properties [new XmlName("", "TargetType")];
+ if (ttnode is ValueNode)
+ typeName = (ttnode as ValueNode).Value as string;
+ else if (ttnode is IElementNode)
+ typeName = ((ttnode as IElementNode).CollectionItems.FirstOrDefault() as ValueNode)?.Value as string ?? ((ttnode as IElementNode).Properties [new XmlName("", "TypeName")] as ValueNode)?.Value as string;
+ }
+ } else if ((node.Parent as ElementNode)?.XmlType.NamespaceUri == "http://xamarin.com/schemas/2014/forms" && (node.Parent as ElementNode)?.XmlType.Name == "Trigger")
+ typeName = ((node.Parent as ElementNode).Properties [new XmlName("", "TargetType")] as ValueNode).Value as string;
+ propertyName = parts [0];
+ } else if (parts.Length == 2) {
+ typeName = parts [0];
+ propertyName = parts [1];
+ } else
+ throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(BindableProperty)}", node);
+
+ var typeRef = GetTypeReference(typeName, module, node);
+ if (typeRef == null)
+ throw new XamlParseException($"Can't resolve {typeName}", node);
+ bpRef = GetBindablePropertyFieldReference(typeRef, propertyName, module);
+ if (bpRef == null)
+ throw new XamlParseException($"Can't resolve {propertyName} on {typeRef.Name}", node);
+ yield return Instruction.Create(OpCodes.Ldsfld, bpRef);
+ }
+
+ public static TypeReference GetTypeReference(string xmlType, ModuleDefinition module, BaseNode iNode)
+ {
+ var split = xmlType.Split(':');
+ if (split.Length > 2)
+ throw new XamlParseException($"Type \"{xmlType}\" is invalid", iNode);
+
+ string prefix, name;
+ if (split.Length == 2) {
+ prefix = split [0];
+ name = split [1];
+ } else {
+ prefix = "";
+ name = split [0];
+ }
+ var namespaceuri = iNode.NamespaceResolver.LookupNamespace(prefix) ?? "";
+ return XmlTypeExtensions.GetTypeReference(namespaceuri, name, module, iNode);
+ }
+
+ public static FieldReference GetBindablePropertyFieldReference(TypeReference typeRef, string propertyName, ModuleDefinition module)
+ {
+ TypeReference declaringTypeReference;
+ FieldReference bpRef = typeRef.GetField(fd => fd.Name == $"{propertyName}Property" && fd.IsStatic && fd.IsPublic, out declaringTypeReference);
+ if (bpRef != null) {
+ bpRef = module.Import(bpRef.ResolveGenericParameters(declaringTypeReference));
+ bpRef.FieldType = module.Import(bpRef.FieldType);
+ }
+ return bpRef;
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Build.Tasks/CompiledConverters/BindingTypeConverter.cs b/Xamarin.Forms.Build.Tasks/CompiledConverters/BindingTypeConverter.cs
new file mode 100644
index 00000000..74990a86
--- /dev/null
+++ b/Xamarin.Forms.Build.Tasks/CompiledConverters/BindingTypeConverter.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Xamarin.Forms.Xaml;
+
+using static System.String;
+
+namespace Xamarin.Forms.Core.XamlC
+{
+ class BindingTypeConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ModuleDefinition module, BaseNode node)
+ {
+ if (IsNullOrEmpty(value))
+ throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(Binding)}", node);
+
+ var bindingCtor = module.Import(typeof(Binding)).Resolve().Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 6);
+ var bindingCtorRef = module.Import(bindingCtor);
+
+ yield return Instruction.Create(OpCodes.Ldstr, value);
+ yield return Instruction.Create(OpCodes.Ldc_I4, (int)BindingMode.Default);
+ yield return Instruction.Create(OpCodes.Ldnull);
+ yield return Instruction.Create(OpCodes.Ldnull);
+ yield return Instruction.Create(OpCodes.Ldnull);
+ yield return Instruction.Create(OpCodes.Ldnull);
+ yield return Instruction.Create(OpCodes.Newobj, bindingCtorRef);
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Build.Tasks/CompiledConverters/BoundsTypeConverter.cs b/Xamarin.Forms.Build.Tasks/CompiledConverters/BoundsTypeConverter.cs
new file mode 100644
index 00000000..1cc64fc5
--- /dev/null
+++ b/Xamarin.Forms.Build.Tasks/CompiledConverters/BoundsTypeConverter.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Xamarin.Forms.Xaml;
+
+namespace Xamarin.Forms.Core.XamlC
+{
+ class BoundsTypeConverter : ICompiledTypeConverter
+ {
+ IEnumerable<Instruction> ICompiledTypeConverter.ConvertFromString(string value, ModuleDefinition module, BaseNode node)
+ {
+ if (string.IsNullOrEmpty(value))
+ throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(Rectangle)}", node);
+
+ double x = -1, y = -1, w = -1, h = -1;
+ bool hasX, hasY, hasW, hasH;
+ var xywh = value.Split(',');
+
+ if (xywh.Length != 2 && xywh.Length != 4)
+ throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(Rectangle)}", node);
+
+ hasX = (xywh.Length == 2 || xywh.Length == 4) && double.TryParse(xywh [0], NumberStyles.Number, CultureInfo.InvariantCulture, out x);
+ hasY = (xywh.Length == 2 || xywh.Length == 4) && double.TryParse(xywh [1], NumberStyles.Number, CultureInfo.InvariantCulture, out y);
+ hasW = xywh.Length == 4 && double.TryParse(xywh [2], NumberStyles.Number, CultureInfo.InvariantCulture, out w);
+ hasH = xywh.Length == 4 && double.TryParse(xywh [3], NumberStyles.Number, CultureInfo.InvariantCulture, out h);
+
+ if (!hasW && xywh.Length == 4 && string.Compare("AutoSize", xywh [2].Trim(), StringComparison.OrdinalIgnoreCase) == 0) {
+ hasW = true;
+ w = AbsoluteLayout.AutoSize;
+ }
+
+ if (!hasH && xywh.Length == 4 && string.Compare("AutoSize", xywh [3].Trim(), StringComparison.OrdinalIgnoreCase) == 0) {
+ hasH = true;
+ h = AbsoluteLayout.AutoSize;
+ }
+
+ if (hasX && hasY && xywh.Length == 2) {
+ hasW = true;
+ w = AbsoluteLayout.AutoSize;
+ hasH = true;
+ h = AbsoluteLayout.AutoSize;
+ }
+
+ if (!hasX || !hasY || !hasW || !hasH)
+ throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(Rectangle)}", node);
+
+ return GenerateIL(x, y, w, h, module);
+ }
+
+ IEnumerable<Instruction> GenerateIL(double x, double y, double w, double h, ModuleDefinition module)
+ {
+// IL_0000: ldc.r8 3.1000000000000001
+// IL_0009: ldc.r8 4.2000000000000002
+// IL_0012: ldc.r8 5.2999999999999998
+// IL_001b: ldc.r8 6.4000000000000004
+// IL_0024: newobj instance void valuetype Test.Rectangle::'.ctor'(float64, float64, float64, float64)
+
+ yield return Instruction.Create(OpCodes.Ldc_R8, x);
+ yield return Instruction.Create(OpCodes.Ldc_R8, y);
+ yield return Instruction.Create(OpCodes.Ldc_R8, w);
+ yield return Instruction.Create(OpCodes.Ldc_R8, h);
+
+ var rectangleCtor = module.Import(typeof(Rectangle)).Resolve().Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 4);
+ var rectangleCtorRef = module.Import(rectangleCtor);
+ yield return Instruction.Create(OpCodes.Newobj, rectangleCtorRef);
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Build.Tasks/CompiledConverters/ColorTypeConverter.cs b/Xamarin.Forms.Build.Tasks/CompiledConverters/ColorTypeConverter.cs
new file mode 100644
index 00000000..39527954
--- /dev/null
+++ b/Xamarin.Forms.Build.Tasks/CompiledConverters/ColorTypeConverter.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Xamarin.Forms.Xaml;
+
+namespace Xamarin.Forms.Core.XamlC
+{
+ class ColorTypeConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ModuleDefinition module, BaseNode node)
+ {
+ do {
+ if (string.IsNullOrEmpty(value))
+ break;
+
+ value = value.Trim();
+
+ if (value.StartsWith("#", StringComparison.Ordinal)) {
+ var color = Color.FromHex(value);
+ yield return Instruction.Create(OpCodes.Ldc_R8, color.R);
+ yield return Instruction.Create(OpCodes.Ldc_R8, color.G);
+ yield return Instruction.Create(OpCodes.Ldc_R8, color.B);
+ yield return Instruction.Create(OpCodes.Ldc_R8, color.A);
+ var colorCtor = module.Import(typeof(Color)).Resolve().Methods.FirstOrDefault(
+ md => md.IsConstructor && md.Parameters.Count == 4 &&
+ md.Parameters.All(p => p.ParameterType.FullName == "System.Double"));
+ var colorCtorRef = module.Import(colorCtor);
+ yield return Instruction.Create(OpCodes.Newobj, colorCtorRef);
+ yield break;
+ }
+ var parts = value.Split('.');
+ if (parts.Length == 1 || (parts.Length == 2 && parts [0] == "Color")) {
+ var color = parts [parts.Length - 1];
+
+ var field = module.Import(typeof(Color)).Resolve().Fields.SingleOrDefault(fd => fd.Name == color && fd.IsStatic);
+ if (field != null) {
+ yield return Instruction.Create(OpCodes.Ldsfld, module.Import(field));
+ yield break;
+ }
+ var propertyGetter = module.Import(typeof(Color)).Resolve().Properties.SingleOrDefault(pd => pd.Name == color && pd.GetMethod.IsStatic)?.GetMethod;
+ if (propertyGetter != null) {
+ yield return Instruction.Create(OpCodes.Call, module.Import(propertyGetter));
+ yield break;
+ }
+ }
+ } while (false);
+
+ throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(Color)}", node);
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Build.Tasks/CompiledConverters/ICompiledTypeConverter.cs b/Xamarin.Forms.Build.Tasks/CompiledConverters/ICompiledTypeConverter.cs
new file mode 100644
index 00000000..5ed88d0a
--- /dev/null
+++ b/Xamarin.Forms.Build.Tasks/CompiledConverters/ICompiledTypeConverter.cs
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+using Mono.Cecil.Cil;
+using Mono.Cecil;
+using System.Xml;
+
+namespace Xamarin.Forms.Xaml
+{
+ interface ICompiledTypeConverter
+ {
+ IEnumerable<Instruction> ConvertFromString(string value, ModuleDefinition module, BaseNode node);
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Build.Tasks/CompiledConverters/LayoutOptionsConverter.cs b/Xamarin.Forms.Build.Tasks/CompiledConverters/LayoutOptionsConverter.cs
new file mode 100644
index 00000000..e252ed9d
--- /dev/null
+++ b/Xamarin.Forms.Build.Tasks/CompiledConverters/LayoutOptionsConverter.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Xamarin.Forms.Xaml;
+
+namespace Xamarin.Forms.Core.XamlC
+{
+ class LayoutOptionsConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ModuleDefinition module, BaseNode node)
+ {
+ do {
+ if (string.IsNullOrEmpty(value))
+ break;
+
+ value = value.Trim();
+
+ var parts = value.Split('.');
+ if (parts.Length == 1 || (parts.Length == 2 && parts [0] == "LayoutOptions")) {
+ var options = parts [parts.Length - 1];
+
+ var field = module.Import(typeof(LayoutOptions)).Resolve().Fields.SingleOrDefault(fd => fd.Name == options && fd.IsStatic);
+ if (field != null) {
+ yield return Instruction.Create(OpCodes.Ldsfld, module.Import(field));
+ yield break;
+ }
+ }
+ } while (false);
+
+ throw new XamlParseException(String.Format("Cannot convert \"{0}\" into {1}", value, typeof(LayoutOptions)), node);
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Build.Tasks/CompiledConverters/RectangleTypeConverter.cs b/Xamarin.Forms.Build.Tasks/CompiledConverters/RectangleTypeConverter.cs
new file mode 100644
index 00000000..af480667
--- /dev/null
+++ b/Xamarin.Forms.Build.Tasks/CompiledConverters/RectangleTypeConverter.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Xamarin.Forms.Xaml;
+
+namespace Xamarin.Forms.Core.XamlC
+{
+ class RectangleTypeConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ModuleDefinition module, BaseNode node)
+ {
+ if (string.IsNullOrEmpty(value))
+ throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(Rectangle)}", node);
+ double x, y, w, h;
+ var xywh = value.Split(',');
+ if (xywh.Length != 4 ||
+ !double.TryParse(xywh [0], NumberStyles.Number, CultureInfo.InvariantCulture, out x) ||
+ !double.TryParse(xywh [1], NumberStyles.Number, CultureInfo.InvariantCulture, out y) ||
+ !double.TryParse(xywh [2], NumberStyles.Number, CultureInfo.InvariantCulture, out w) ||
+ !double.TryParse(xywh [3], NumberStyles.Number, CultureInfo.InvariantCulture, out h))
+ throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(Rectangle)}", node);
+
+ return GenerateIL(x, y, w, h, module);
+ }
+
+ IEnumerable<Instruction> GenerateIL(double x, double y, double w, double h, ModuleDefinition module)
+ {
+// IL_0000: ldc.r8 3.1000000000000001
+// IL_0009: ldc.r8 4.2000000000000002
+// IL_0012: ldc.r8 5.2999999999999998
+// IL_001b: ldc.r8 6.4000000000000004
+// IL_0024: newobj instance void valuetype Test.Rectangle::'.ctor'(float64, float64, float64, float64)
+
+ yield return Instruction.Create(OpCodes.Ldc_R8, x);
+ yield return Instruction.Create(OpCodes.Ldc_R8, y);
+ yield return Instruction.Create(OpCodes.Ldc_R8, w);
+ yield return Instruction.Create(OpCodes.Ldc_R8, h);
+
+ var rectangleCtor = module.Import(typeof(Rectangle)).Resolve().Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 4);
+ var rectangleCtorRef = module.Import(rectangleCtor);
+ yield return Instruction.Create(OpCodes.Newobj, rectangleCtorRef);
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs b/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs
index 449b887f..33a9a7f5 100644
--- a/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs
+++ b/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs
@@ -121,7 +121,7 @@ namespace Xamarin.Forms.Build.Tasks
}
if (parameterizedCtorInfo != null && ValidateCtorArguments(parameterizedCtorInfo, node)) {
ctorInfo = parameterizedCtorInfo;
- // IL_0000: ldstr "foo"
+// IL_0000: ldstr "foo"
Context.IL.Append(PushCtorArguments(parameterizedCtorInfo, node));
}
ctorInfo = ctorInfo ?? typedef.Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters && !md.IsStatic);
@@ -198,9 +198,9 @@ namespace Xamarin.Forms.Build.Tasks
type = type.Contains(":") ? type.Split(':') [1].Trim() : type;
Context.TypeExtensions [node] = new XmlType(namespaceuri, type, null).GetTypeReference(Module, node);
- node.Properties.Clear();
- node.CollectionItems.Clear();
-
+ if (!node.SkipProperties.Contains(new XmlName("", "TypeName")))
+ node.SkipProperties.Add(new XmlName("", "TypeName"));
+
var vardefref = new VariableDefinitionReference(vardef);
Context.IL.Append(SetPropertiesVisitor.ProvideValue(vardefref, Context, Module, node));
if (vardef != vardefref.VariableDefinition) {
@@ -213,8 +213,8 @@ namespace Xamarin.Forms.Build.Tasks
public void Visit(RootNode node, INode parentNode)
{
- // IL_0013: ldarg.0
- // IL_0014: stloc.3
+// IL_0013: ldarg.0
+// IL_0014: stloc.3
var ilnode = (ILRootNode)node;
var typeref = ilnode.TypeReference;
@@ -256,7 +256,8 @@ namespace Xamarin.Forms.Build.Tasks
.ConstructorArguments.First()
.Value as string;
var node = enode.Properties[new XmlName("", propname)];
- enode.Properties.Remove(new XmlName("", propname));
+ if (!enode.SkipProperties.Contains(new XmlName("", propname)))
+ enode.SkipProperties.Add(new XmlName("", propname));
VariableDefinition vardef;
ValueNode vnode = null;
diff --git a/Xamarin.Forms.Build.Tasks/ExpandMarkupsVisitor.cs b/Xamarin.Forms.Build.Tasks/ExpandMarkupsVisitor.cs
index feafe214..26e241ab 100644
--- a/Xamarin.Forms.Build.Tasks/ExpandMarkupsVisitor.cs
+++ b/Xamarin.Forms.Build.Tasks/ExpandMarkupsVisitor.cs
@@ -49,6 +49,8 @@ namespace Xamarin.Forms.Build.Tasks
return;
if (skips.Contains(propertyName))
return;
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
+ return;
var markupString = markupnode.MarkupString;
var node = ParseExpression(ref markupString, Context, markupnode.NamespaceResolver, markupnode) as IElementNode;
if (node != null)
diff --git a/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs b/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs
index 084151ba..a7fed895 100644
--- a/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs
+++ b/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs
@@ -51,6 +51,21 @@ namespace Xamarin.Forms.Build.Tasks
var module = context.Body.Method.Module;
var str = (string)node.Value;
+ //If the TypeConverter has a ProvideCompiledAttribute that can be resolved, shortcut this
+ var compiledConverterName = typeConverter?.GetCustomAttribute (module.Import(typeof(ProvideCompiledAttribute)))?.ConstructorArguments?.First().Value as string;
+ Type compiledConverterType;
+ if (compiledConverterName != null && (compiledConverterType = Type.GetType (compiledConverterName)) != null) {
+ var compiledConverter = Activator.CreateInstance (compiledConverterType);
+ var converter = typeof(ICompiledTypeConverter).GetMethods ().FirstOrDefault (md => md.Name == "ConvertFromString");
+ var instructions = (IEnumerable<Instruction>)converter.Invoke (compiledConverter, new object[] {
+ node.Value as string, context.Body.Method.Module, node as BaseNode});
+ foreach (var i in instructions)
+ yield return i;
+ if (targetTypeRef.IsValueType && boxValueTypes)
+ yield return Instruction.Create (OpCodes.Box, module.Import (targetTypeRef));
+ yield break;
+ }
+
//If there's a [TypeConverter], use it
if (typeConverter != null)
{
diff --git a/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs b/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs
index 734a34c2..f481cbee 100644
--- a/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs
+++ b/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs
@@ -60,6 +60,8 @@ namespace Xamarin.Forms.Build.Tasks
if (skips.Contains(propertyName))
return;
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
+ return;
if (propertyName.NamespaceURI == "http://schemas.openxmlformats.org/markup-compatibility/2006" &&
propertyName.LocalName == "Ignorable")
return;
@@ -105,6 +107,11 @@ namespace Xamarin.Forms.Build.Tasks
if (propertyName != XmlName.Empty)
{
+ if (skips.Contains(propertyName))
+ return;
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
+ return;
+
if (propertyName == XmlName._CreateContent)
SetDataTemplate((IElementNode)parentNode, node, Context, node);
else
@@ -136,6 +143,8 @@ namespace Xamarin.Forms.Build.Tasks
var name = new XmlName(node.NamespaceURI, contentProperty);
if (skips.Contains(name))
return;
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
+ return;
Context.IL.Append(SetPropertyValue(Context.Variables[(IElementNode)parentNode], name, node, Context, node));
}
}
@@ -151,7 +160,8 @@ namespace Xamarin.Forms.Build.Tasks
if (skips.Contains(parentList.XmlName))
return;
-
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
+ return;
var elementType = parent.VariableType;
var localname = parentList.XmlName.LocalName;
@@ -775,4 +785,4 @@ namespace Xamarin.Forms.Build.Tasks
return vardefref.VariableDefinition;
}
}
-} \ No newline at end of file
+}
diff --git a/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj b/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj
index d24f42fc..b7250038 100644
--- a/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj
+++ b/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj
@@ -91,6 +91,13 @@
<Compile Include="CompiledMarkupExtensions\StaticExtension.cs" />
<Compile Include="CompiledMarkupExtensions\ICompiledMarkupExtension.cs" />
<Compile Include="BindablePropertyReferenceExtensions.cs" />
+ <Compile Include="CompiledConverters\BindablePropertyConverter.cs" />
+ <Compile Include="CompiledConverters\BindingTypeConverter.cs" />
+ <Compile Include="CompiledConverters\BoundsTypeConverter.cs" />
+ <Compile Include="CompiledConverters\ColorTypeConverter.cs" />
+ <Compile Include="CompiledConverters\ICompiledTypeConverter.cs" />
+ <Compile Include="CompiledConverters\LayoutOptionsConverter.cs" />
+ <Compile Include="CompiledConverters\RectangleTypeConverter.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Target Name="AfterBuild">
@@ -126,4 +133,7 @@
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
</Target>
+ <ItemGroup>
+ <Folder Include="CompiledConverters\" />
+ </ItemGroup>
</Project>
diff --git a/Xamarin.Forms.Build.Tasks/XmlTypeExtensions.cs b/Xamarin.Forms.Build.Tasks/XmlTypeExtensions.cs
index 52460418..db182847 100644
--- a/Xamarin.Forms.Build.Tasks/XmlTypeExtensions.cs
+++ b/Xamarin.Forms.Build.Tasks/XmlTypeExtensions.cs
@@ -10,6 +10,11 @@ namespace Xamarin.Forms.Build.Tasks
{
static class XmlTypeExtensions
{
+ public static TypeReference GetTypeReference (string namespaceURI, string typename, ModuleDefinition module, IXmlLineInfo xmlInfo)
+ {
+ return new XmlType (namespaceURI, typename, null).GetTypeReference (module, xmlInfo);
+ }
+
public static TypeReference GetTypeReference(this XmlType xmlType, ModuleDefinition module, IXmlLineInfo xmlInfo)
{
var namespaceURI = xmlType.NamespaceUri;