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 XamlValueTargetProvider(object targetObject, INode node, HydratationContext context, object targetProperty) { Context = context; Node = node; TargetObject = targetObject; TargetProperty = targetProperty; }
public void TestFailOnMissingOrWrongConverter() { var node = new ValueNode("baz", new MockNameSpaceResolver()); var bindable = new Bindable(); Assert.IsNull(bindable.Baz); var rootNode = new XamlLoader.RuntimeRootNode(new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests", "Bindable", null), bindable, null) { Properties = { { new XmlName(null, "Baz"), node }, } }; var context = new HydratationContext { RootElement = new Label() }; rootNode.Accept(new CreateValuesVisitor(context), null); Assert.Throws <XamlParseException>(() => node.Accept(new ApplyPropertiesVisitor(context), rootNode)); }
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 void TestSetPropertyWithoutConverter() { var baz = new Baz(); var node = new ValueNode(baz, new MockNameSpaceResolver()); var bindable = new Bindable(); Assert.IsNull(bindable.Baz); var rootNode = new XamlLoader.RuntimeRootNode(new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests", "Bindable", null), bindable, null) { Properties = { { new XmlName(null, "Baz"), node }, } }; var context = new HydratationContext { RootElement = new Label() }; rootNode.Accept(new CreateValuesVisitor(context), null); node.Accept(new ApplyPropertiesVisitor(context), rootNode); Assert.AreEqual(baz, bindable.Baz); }
public void TestConvertAttachedBindableProperty() { var node = new ValueNode("qux", new MockNameSpaceResolver()); var bindable = new Bindable(); Assert.IsNull(Bindable.GetQux(bindable)); var rootNode = new XamlLoader.RuntimeRootNode(new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests", "Bindable", null), bindable, null) { Properties = { { new XmlName("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests", "Bindable.Qux"), node }, } }; var context = new HydratationContext { RootElement = new Label() }; rootNode.Accept(new CreateValuesVisitor(context), null); node.Accept(new ApplyPropertiesVisitor(context), rootNode); Assert.IsNotNull(Bindable.GetQux(bindable)); Assert.That(Bindable.GetQux(bindable), Is.TypeOf <Qux> ()); Assert.AreEqual("qux", Bindable.GetQux(bindable).Value); }
public void TestConvertWithAttributeOnType() { var node = new ValueNode("foobar", new MockNameSpaceResolver()); var bindable = new Bindable(); Assert.IsNull(bindable.FooBar); var rootNode = new XamlLoader.RuntimeRootNode(new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests", "Bindable", null), bindable, null) { Properties = { { new XmlName(null, "FooBar"), node }, } }; var context = new HydratationContext { RootElement = new Label() }; rootNode.Accept(new CreateValuesVisitor(context), null); node.Accept(new ApplyPropertiesVisitor(context), rootNode); Assert.IsNotNull(bindable.FooBar); Assert.That(bindable.FooBar, Is.TypeOf <FooBar> ()); Assert.AreEqual("foobar", bindable.FooBar.Value); }
public static object Create (string xaml, bool doNotThrow = false) { object inflatedView = null; using (var reader = XmlReader.Create (new StringReader (xaml))) { while (reader.Read ()) { //Skip until element if (reader.NodeType == XmlNodeType.Whitespace) continue; if (reader.NodeType != XmlNodeType.Element) { Debug.WriteLine ("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value); continue; } var rootnode = new RuntimeRootNode (new XmlType (reader.NamespaceURI, reader.Name, null), null, (IXmlNamespaceResolver)reader); XamlParser.ParseXaml (rootnode, reader); var visitorContext = new HydratationContext { DoNotThrowOnExceptions = doNotThrow, }; var cvv = new CreateValuesVisitor (visitorContext); cvv.Visit ((ElementNode)rootnode, null); inflatedView = rootnode.Root = visitorContext.Values [rootnode]; visitorContext.RootElement = inflatedView as BindableObject; Visit (rootnode, visitorContext); break; } } return inflatedView; }
static void Visit (RootNode rootnode, HydratationContext visitorContext) { rootnode.Accept (new XamlNodeVisitor ((node, parent) => node.Parent = parent), null); //set parents for {StaticResource} rootnode.Accept (new ExpandMarkupsVisitor (visitorContext), null); rootnode.Accept (new NamescopingVisitor (visitorContext), null); //set namescopes for {x:Reference} rootnode.Accept (new CreateValuesVisitor (visitorContext), null); rootnode.Accept (new RegisterXNamesVisitor (visitorContext), null); rootnode.Accept (new FillResourceDictionariesVisitor (visitorContext), null); rootnode.Accept (new ApplyPropertiesVisitor (visitorContext, true), null); }
void SetTemplate(ElementTemplate dt, INode node) { #pragma warning disable 0612 ((IDataTemplate)dt).LoadTemplate = () => { #pragma warning restore 0612 var context = new HydratationContext { ParentContext = Context, RootElement = Context.RootElement }; node.Accept(new ExpandMarkupsVisitor(context), null); node.Accept(new NamescopingVisitor(context), null); node.Accept(new CreateValuesVisitor(context), null); node.Accept(new RegisterXNamesVisitor(context), null); node.Accept(new FillResourceDictionariesVisitor(context), null); node.Accept(new ApplyPropertiesVisitor(context, true), null); return context.Values[node]; }; }
public static void SetPropertyValue(object xamlelement, XmlName propertyName, object value, object rootElement, INode node, HydratationContext context, IXmlLineInfo lineInfo) { var elementType = xamlelement.GetType(); var localname = propertyName.LocalName; var serviceProvider = new XamlServiceProvider(node, context); //If it's an attached BP, update elementType and propertyName var attached = GetRealNameAndType(ref elementType, propertyName.NamespaceURI, ref localname, context, lineInfo); //If the target is an event, connect var eventInfo = elementType.GetRuntimeEvent(localname); if (eventInfo != null && value is string) { var methodInfo = rootElement.GetType().GetRuntimeMethods().FirstOrDefault(mi => mi.Name == (string)value); if (methodInfo == null) { var xpe = new XamlParseException (string.Format ("No method {0} found on type {1}", value, rootElement.GetType ()), lineInfo); if (context.DoNotThrowOnExceptions) { System.Diagnostics.Debug.WriteLine (xpe.Message); return; } else throw xpe; } try { eventInfo.AddEventHandler(xamlelement, methodInfo.CreateDelegate(eventInfo.EventHandlerType, rootElement)); } catch (ArgumentException) { var xpe = new XamlParseException (string.Format ("Method {0} does not have the correct signature", value), lineInfo); if (context.DoNotThrowOnExceptions) System.Diagnostics.Debug.WriteLine (xpe.Message); else throw xpe; } return; } var property = GetBindableProperty(elementType, localname, lineInfo, false); //If Value is DynamicResource and it's a BP, SetDynamicResource if (value is DynamicResource && property != null) { if (!(xamlelement.GetType()).GetTypeInfo().IsSubclassOf(typeof (BindableObject))) throw new XamlParseException(string.Format("{0} is not a BindableObject", xamlelement.GetType().Name), lineInfo); ((BindableObject)xamlelement).SetDynamicResource(property, ((DynamicResource)value).Key); return; } //If value is BindingBase, and target is a BindableProperty, SetBinding if (value is BindingBase && property != null) { if (!(xamlelement.GetType()).GetTypeInfo().IsSubclassOf(typeof (BindableObject))) throw new XamlParseException(string.Format("{0} is not a BindableObject", xamlelement.GetType().Name), lineInfo); ((BindableObject)xamlelement).SetBinding(property, value as BindingBase); return; } //If it's a BindableProberty, SetValue if (property != null) { if (!(xamlelement.GetType()).GetTypeInfo().IsSubclassOf(typeof (BindableObject))) throw new XamlParseException(string.Format("{0} is not a BindableObject", xamlelement.GetType().Name), lineInfo); Func<MemberInfo> minforetriever; if (attached) minforetriever = () => elementType.GetRuntimeMethod("Get" + localname, new[] { typeof (BindableObject) }); else minforetriever = () => elementType.GetRuntimeProperty(localname); var convertedValue = value.ConvertTo(property.ReturnType, minforetriever, serviceProvider); //SetValue doesn't throw on mismatching type, so check before to get a chance to try the property setting or the collection adding var nullable = property.ReturnTypeInfo.IsGenericType && property.ReturnTypeInfo.GetGenericTypeDefinition() == typeof (Nullable<>); if ((convertedValue == null && (!property.ReturnTypeInfo.IsValueType || nullable)) || (property.ReturnType.IsInstanceOfType(convertedValue))) { ((BindableObject)xamlelement).SetValue(property, convertedValue); return; } } var exception = new XamlParseException( String.Format("No Property of name {0} found", propertyName.LocalName), lineInfo); //If we can assign that value to a normal property, let's do it var propertyInfo = elementType.GetRuntimeProperties().FirstOrDefault(p => p.Name == localname); MethodInfo setter; if (propertyInfo != null && propertyInfo.CanWrite && (setter = propertyInfo.SetMethod) != null) { object convertedValue = value.ConvertTo(propertyInfo.PropertyType, () => propertyInfo, serviceProvider); if (convertedValue == null || propertyInfo.PropertyType.IsInstanceOfType(convertedValue)) { try { setter.Invoke(xamlelement, new[] { convertedValue }); return; } catch (ArgumentException) { } } else { exception = new XamlParseException( String.Format("Cannot assign property \"{0}\": type mismatch between \"{1}\" and \"{2}\"", propertyName.LocalName, value.GetType(), propertyInfo.PropertyType), lineInfo); } } //If it's an already initialized property, add to it MethodInfo getter; if (propertyInfo != null && propertyInfo.CanRead && (getter = propertyInfo.GetMethod) != null) { IEnumerable collection; MethodInfo addMethod; if ((collection = getter.Invoke(xamlelement, new object[] { }) as IEnumerable) != null && (addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) != null) { addMethod.Invoke(collection, new[] { value.ConvertTo(propertyInfo.PropertyType, (Func<TypeConverter>)null, serviceProvider) }); return; } } if (context.DoNotThrowOnExceptions) System.Diagnostics.Debug.WriteLine (exception.Message); else throw exception; }
static bool GetRealNameAndType(ref Type elementType, string namespaceURI, ref string localname, HydratationContext context, IXmlLineInfo lineInfo) { var dotIdx = localname.IndexOf('.'); if (dotIdx > 0) { var typename = localname.Substring(0, dotIdx); localname = localname.Substring(dotIdx + 1); XamlParseException xpe; elementType = XamlParser.GetElementType(new XmlType(namespaceURI, typename, null), lineInfo, context.RootElement.GetType().GetTypeInfo().Assembly, out xpe); if (xpe != null) throw xpe; return true; } return false; }
public ApplyPropertiesVisitor(HydratationContext context, bool stopOnResourceDictionary = false) { Context = context; StopOnResourceDictionary = stopOnResourceDictionary; }
public void TestFailOnMissingOrWrongConverter () { var node = new ValueNode ("baz", new MockNameSpaceResolver()); var bindable = new Bindable (); Assert.IsNull (bindable.Baz); var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable, null) { Properties = { { new XmlName (null, "Baz"), node }, } }; var context = new HydratationContext { RootElement = new Label () }; rootNode.Accept (new CreateValuesVisitor (context), null); Assert.Throws<XamlParseException>(()=> node.Accept (new ApplyPropertiesVisitor (context), rootNode)); }
public RegisterXNamesVisitor(HydratationContext context) { Values = context.Values; }
public CreateValuesVisitor(HydratationContext context) { Context = context; }
public NamescopingVisitor(HydratationContext context) { Values = context.Values; }
public void TestConvertAttachedBindableProperty () { var node = new ValueNode ("qux", new MockNameSpaceResolver()); var bindable = new Bindable (); Assert.IsNull (Bindable.GetQux (bindable)); var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable, null) { Properties = { { new XmlName ("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests", "Bindable.Qux"), node }, } }; var context = new HydratationContext { RootElement = new Label () }; rootNode.Accept (new CreateValuesVisitor (context), null); node.Accept (new ApplyPropertiesVisitor (context), rootNode); Assert.IsNotNull (Bindable.GetQux (bindable)); Assert.That (Bindable.GetQux (bindable), Is.TypeOf<Qux> ()); Assert.AreEqual ("qux", Bindable.GetQux (bindable).Value); }
public void TestSetPropertyWithoutConverter () { var baz = new Baz (); var node = new ValueNode (baz, new MockNameSpaceResolver()); var bindable = new Bindable (); Assert.IsNull (bindable.Baz); var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable, null) { Properties = { { new XmlName (null, "Baz"), node }, } }; var context = new HydratationContext { RootElement = new Label () }; rootNode.Accept (new CreateValuesVisitor(context), null); node.Accept (new ApplyPropertiesVisitor (context), rootNode); Assert.AreEqual (baz, bindable.Baz); }
public void TestConvertWithAttributeOnType () { var node = new ValueNode ("foobar", new MockNameSpaceResolver()); var bindable = new Bindable (); Assert.IsNull (bindable.FooBar); var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable, null) { Properties = { { new XmlName (null, "FooBar"), node }, } }; var context = new HydratationContext { RootElement = new Label () }; rootNode.Accept (new CreateValuesVisitor (context), null); node.Accept (new ApplyPropertiesVisitor (context), rootNode); Assert.IsNotNull (bindable.FooBar); Assert.That (bindable.FooBar, Is.TypeOf<FooBar> ()); Assert.AreEqual ("foobar", bindable.FooBar.Value); }