summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Core/BindablePropertyConverter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Core/BindablePropertyConverter.cs')
-rw-r--r--Xamarin.Forms.Core/BindablePropertyConverter.cs105
1 files changed, 105 insertions, 0 deletions
diff --git a/Xamarin.Forms.Core/BindablePropertyConverter.cs b/Xamarin.Forms.Core/BindablePropertyConverter.cs
new file mode 100644
index 00000000..af3fd5b6
--- /dev/null
+++ b/Xamarin.Forms.Core/BindablePropertyConverter.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Xml;
+using Xamarin.Forms.Xaml;
+
+namespace Xamarin.Forms
+{
+ public sealed class BindablePropertyConverter : TypeConverter, IExtendedTypeConverter
+ {
+ object IExtendedTypeConverter.ConvertFrom(CultureInfo culture, object value, IServiceProvider serviceProvider)
+ {
+ return ((IExtendedTypeConverter)this).ConvertFromInvariantString(value as string, serviceProvider);
+ }
+
+ object IExtendedTypeConverter.ConvertFromInvariantString(string value, IServiceProvider serviceProvider)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ return null;
+ if (serviceProvider == null)
+ return null;
+ var parentValuesProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideParentValues;
+ var typeResolver = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver;
+ if (typeResolver == null)
+ return null;
+ IXmlLineInfo lineinfo = null;
+ var xmlLineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ if (xmlLineInfoProvider != null)
+ lineinfo = xmlLineInfoProvider.XmlLineInfo;
+ string[] parts = value.Split('.');
+ Type type = null;
+ if (parts.Length == 1)
+ {
+ if (parentValuesProvider == null)
+ {
+ string msg = string.Format("Can't resolve {0}", parts[0]);
+ throw new XamlParseException(msg, lineinfo);
+ }
+ object parent = parentValuesProvider.ParentObjects.Skip(1).FirstOrDefault();
+ if (parentValuesProvider.TargetObject is Setter)
+ {
+ var style = parent as Style;
+ var triggerBase = parent as TriggerBase;
+ if (style != null)
+ type = style.TargetType;
+ else if (triggerBase != null)
+ type = triggerBase.TargetType;
+ }
+ else if (parentValuesProvider.TargetObject is Trigger)
+ type = (parentValuesProvider.TargetObject as Trigger).TargetType;
+
+ if (type == null)
+ {
+ string msg = string.Format("Can't resolve {0}", parts[0]);
+ throw new XamlParseException(msg, lineinfo);
+ }
+
+ return ConvertFrom(type, parts[0], lineinfo);
+ }
+ if (parts.Length == 2)
+ {
+ if (!typeResolver.TryResolve(parts[0], out type))
+ {
+ string msg = string.Format("Can't resolve {0}", parts[0]);
+ throw new XamlParseException(msg, lineinfo);
+ }
+ return ConvertFrom(type, parts[1], lineinfo);
+ }
+ string emsg = string.Format("Can't resolve {0}. Syntax is [[ns:]Type.]PropertyName.", value);
+ throw new XamlParseException(emsg, lineinfo);
+ }
+
+ public override object ConvertFromInvariantString(string value)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ return null;
+ if (value.Contains(":"))
+ {
+ Log.Warning(null, "Can't resolve properties with xml namespace prefix.");
+ return null;
+ }
+ string[] parts = value.Split('.');
+ if (parts.Length != 2)
+ {
+ Log.Warning(null, "Can't resolve {0}. Accepted syntax is Type.PropertyName.", value);
+ return null;
+ }
+ Type type = Type.GetType("Xamarin.Forms." + parts[0]);
+ return ConvertFrom(type, parts[1], null);
+ }
+
+ BindableProperty ConvertFrom(Type type, string propertyName, IXmlLineInfo lineinfo)
+ {
+ string name = propertyName + "Property";
+ FieldInfo bpinfo = type.GetField(fi => fi.Name == name && fi.IsStatic && fi.IsPublic && fi.FieldType == typeof(BindableProperty));
+ if (bpinfo == null)
+ throw new XamlParseException(string.Format("Can't resolve {0} on {1}", name, type.Name), lineinfo);
+ var bp = bpinfo.GetValue(null) as BindableProperty;
+ if (bp.PropertyName != propertyName)
+ throw new XamlParseException(string.Format("The PropertyName of {0}.{1} is not {2}", type.Name, name, propertyName), lineinfo);
+ return bp;
+ }
+ }
+} \ No newline at end of file