summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Xaml/XamlServiceProvider.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Xaml/XamlServiceProvider.cs')
-rw-r--r--Xamarin.Forms.Xaml/XamlServiceProvider.cs309
1 files changed, 309 insertions, 0 deletions
diff --git a/Xamarin.Forms.Xaml/XamlServiceProvider.cs b/Xamarin.Forms.Xaml/XamlServiceProvider.cs
new file mode 100644
index 00000000..8998e6f5
--- /dev/null
+++ b/Xamarin.Forms.Xaml/XamlServiceProvider.cs
@@ -0,0 +1,309 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Xml;
+using Xamarin.Forms.Internals;
+
+namespace Xamarin.Forms.Xaml.Internals
+{
+ public class XamlServiceProvider : IServiceProvider
+ {
+ readonly Dictionary<Type, object> services = new Dictionary<Type, object>();
+
+ internal XamlServiceProvider(INode node, HydratationContext context)
+ {
+ object targetObject;
+ if (node != null && node.Parent != null && context.Values.TryGetValue(node.Parent, out targetObject))
+ IProvideValueTarget = new XamlValueTargetProvider(targetObject, node, context, null);
+ if (context != null)
+ IRootObjectProvider = new XamlRootObjectProvider(context.RootElement);
+ if (node != null)
+ {
+ IXamlTypeResolver = new XamlTypeResolver(node.NamespaceResolver, XamlParser.GetElementType,
+ context.RootElement.GetType().GetTypeInfo().Assembly);
+
+ var enode = node;
+ while (enode != null && !(enode is IElementNode))
+ enode = enode.Parent;
+ if (enode != null)
+ INameScopeProvider = new NameScopeProvider { NameScope = (enode as IElementNode).Namescope };
+ }
+
+ var xmlLineInfo = node as IXmlLineInfo;
+ if (xmlLineInfo != null)
+ IXmlLineInfoProvider = new XmlLineInfoProvider(xmlLineInfo);
+
+ IValueConverterProvider = new ValueConverterProvider();
+ }
+
+ public XamlServiceProvider()
+ {
+ IValueConverterProvider = new ValueConverterProvider();
+ }
+
+ internal IProvideValueTarget IProvideValueTarget
+ {
+ get { return (IProvideValueTarget)GetService(typeof (IProvideValueTarget)); }
+ set { services[typeof (IProvideValueTarget)] = value; }
+ }
+
+ internal IXamlTypeResolver IXamlTypeResolver
+ {
+ get { return (IXamlTypeResolver)GetService(typeof (IXamlTypeResolver)); }
+ set { services[typeof (IXamlTypeResolver)] = value; }
+ }
+
+ internal IRootObjectProvider IRootObjectProvider
+ {
+ get { return (IRootObjectProvider)GetService(typeof (IRootObjectProvider)); }
+ set { services[typeof (IRootObjectProvider)] = value; }
+ }
+
+ internal IXmlLineInfoProvider IXmlLineInfoProvider
+ {
+ get { return (IXmlLineInfoProvider)GetService(typeof (IXmlLineInfoProvider)); }
+ set { services[typeof (IXmlLineInfoProvider)] = value; }
+ }
+
+ internal INameScopeProvider INameScopeProvider
+ {
+ get { return (INameScopeProvider)GetService(typeof (INameScopeProvider)); }
+ set { services[typeof (INameScopeProvider)] = value; }
+ }
+
+ internal IValueConverterProvider IValueConverterProvider
+ {
+ get { return (IValueConverterProvider)GetService(typeof (IValueConverterProvider)); }
+ set { services[typeof (IValueConverterProvider)] = value; }
+ }
+
+ public object GetService(Type serviceType)
+ {
+ object service;
+ return services.TryGetValue(serviceType, out service) ? service : null;
+ }
+
+ public void Add(Type type, object service)
+ {
+ services.Add(type, service);
+ }
+ }
+
+ internal class XamlValueTargetProvider : IProvideParentValues, IProvideValueTarget
+ {
+ public XamlValueTargetProvider(object targetObject, INode node, HydratationContext context, object targetProperty)
+ {
+ Context = context;
+ Node = node;
+ TargetObject = targetObject;
+ TargetProperty = targetProperty;
+ }
+
+ INode Node { get; }
+
+ HydratationContext Context { get; }
+
+ public object TargetObject { get; }
+
+ public object TargetProperty
+ {
+ get { throw new NotImplementedException(); }
+ private set { }
+ }
+
+ IEnumerable<object> IProvideParentValues.ParentObjects
+ {
+ get
+ {
+ if (Node == null || Context == null)
+ yield break;
+ var n = Node;
+ object obj = null;
+ var context = Context;
+ while (n.Parent != null && context != null)
+ {
+ if (n.Parent is IElementNode)
+ {
+ if (context.Values.TryGetValue(n.Parent, out obj))
+ yield return obj;
+ else
+ {
+ context = context.ParentContext;
+ continue;
+ }
+ }
+ n = n.Parent;
+ }
+ }
+ }
+ }
+
+ public class SimpleValueTargetProvider : IProvideParentValues, IProvideValueTarget
+ {
+ readonly object[] objectAndParents;
+
+ public SimpleValueTargetProvider(object[] objectAndParents)
+ {
+ if (objectAndParents == null)
+ throw new ArgumentNullException("objectAndParents");
+ if (objectAndParents.Length == 0)
+ throw new ArgumentException();
+
+ this.objectAndParents = objectAndParents;
+ }
+
+ IEnumerable<object> IProvideParentValues.ParentObjects
+ {
+ get { return objectAndParents; }
+ }
+
+ object IProvideValueTarget.TargetObject
+ {
+ get { return objectAndParents[0]; }
+ }
+
+ object IProvideValueTarget.TargetProperty
+ {
+ get { throw new NotImplementedException(); }
+ }
+ }
+
+ public class XamlTypeResolver : IXamlTypeResolver
+ {
+ readonly Assembly currentAssembly;
+ readonly GetTypeFromXmlName getTypeFromXmlName;
+ readonly IXmlNamespaceResolver namespaceResolver;
+
+ public XamlTypeResolver(IXmlNamespaceResolver namespaceResolver, Assembly currentAssembly)
+ : this(namespaceResolver, XamlParser.GetElementType, currentAssembly)
+ {
+ }
+
+ internal XamlTypeResolver(IXmlNamespaceResolver namespaceResolver, GetTypeFromXmlName getTypeFromXmlName,
+ Assembly currentAssembly)
+ {
+ this.currentAssembly = currentAssembly;
+ if (namespaceResolver == null)
+ throw new ArgumentNullException();
+ if (getTypeFromXmlName == null)
+ throw new ArgumentNullException();
+
+ this.namespaceResolver = namespaceResolver;
+ this.getTypeFromXmlName = getTypeFromXmlName;
+ }
+
+ Type IXamlTypeResolver.Resolve(string qualifiedTypeName, IServiceProvider serviceProvider)
+ {
+ XamlParseException e;
+ var type = Resolve(qualifiedTypeName, serviceProvider, out e);
+ if (e != null)
+ throw e;
+ return type;
+ }
+
+ bool IXamlTypeResolver.TryResolve(string qualifiedTypeName, out Type type)
+ {
+ XamlParseException exception;
+ type = Resolve(qualifiedTypeName, null, out exception);
+ return exception == null;
+ }
+
+ Type Resolve(string qualifiedTypeName, IServiceProvider serviceProvider, out XamlParseException exception)
+ {
+ exception = null;
+ var split = qualifiedTypeName.Split(':');
+ if (split.Length > 2)
+ return null;
+
+ string prefix, name;
+ if (split.Length == 2)
+ {
+ prefix = split[0];
+ name = split[1];
+ }
+ else
+ {
+ prefix = "";
+ name = split[0];
+ }
+
+ IXmlLineInfo xmlLineInfo = null;
+ if (serviceProvider != null)
+ {
+ var lineInfoProvider = serviceProvider.GetService(typeof (IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ if (lineInfoProvider != null)
+ xmlLineInfo = lineInfoProvider.XmlLineInfo;
+ }
+
+ var namespaceuri = string.IsNullOrEmpty(prefix) ? "" : namespaceResolver.LookupNamespace(prefix);
+ if (namespaceuri == null)
+ {
+ exception = new XamlParseException(string.Format("No xmlns declaration for prefix \"{0}\"", prefix), xmlLineInfo);
+ return null;
+ }
+
+ return getTypeFromXmlName(new XmlType(namespaceuri, name, null), xmlLineInfo, currentAssembly, out exception);
+ }
+
+ internal delegate Type GetTypeFromXmlName(
+ XmlType xmlType, IXmlLineInfo xmlInfo, Assembly currentAssembly, out XamlParseException exception);
+ }
+
+ internal class XamlRootObjectProvider : IRootObjectProvider
+ {
+ public XamlRootObjectProvider(object rootObject)
+ {
+ RootObject = rootObject;
+ }
+
+ public object RootObject { get; }
+ }
+
+ public class XmlLineInfoProvider : IXmlLineInfoProvider
+ {
+ public XmlLineInfoProvider(IXmlLineInfo xmlLineInfo)
+ {
+ XmlLineInfo = xmlLineInfo;
+ }
+
+ public IXmlLineInfo XmlLineInfo { get; }
+ }
+
+ internal interface INameScopeProvider
+ {
+ INameScope NameScope { get; }
+ }
+
+ public class NameScopeProvider : INameScopeProvider
+ {
+ public INameScope NameScope { get; set; }
+ }
+
+ public class XmlNamespaceResolver : IXmlNamespaceResolver
+ {
+ readonly Dictionary<string, string> namespaces = new Dictionary<string, string>();
+
+ public IDictionary<string, string> GetNamespacesInScope(XmlNamespaceScope scope)
+ {
+ throw new NotImplementedException();
+ }
+
+ public string LookupNamespace(string prefix)
+ {
+ string result;
+ if (namespaces.TryGetValue(prefix, out result))
+ return result;
+ return null;
+ }
+
+ public string LookupPrefix(string namespaceName)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Add(string prefix, string ns)
+ {
+ namespaces.Add(prefix, ns);
+ }
+ }
+} \ No newline at end of file