summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Build.Tasks/CompiledConverters/BindablePropertyConverter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Build.Tasks/CompiledConverters/BindablePropertyConverter.cs')
-rw-r--r--Xamarin.Forms.Build.Tasks/CompiledConverters/BindablePropertyConverter.cs84
1 files changed, 84 insertions, 0 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