コード例 #1
0
		public void Visit(ValueNode node, INode parentNode)
		{
			XmlName propertyName;
			if (!SetPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName))
			{
				if (!IsCollectionItem(node, parentNode))
					return;
				string contentProperty;
				if (!Context.Variables.ContainsKey((IElementNode)parentNode))
					return;
				var parentVar = Context.Variables[(IElementNode)parentNode];
				if ((contentProperty = SetPropertiesVisitor.GetContentProperty(parentVar.VariableType)) != null)
					propertyName = new XmlName(((IElementNode)parentNode).NamespaceURI, contentProperty);
				else
					return;
			}

			if (node.SkipPrefix((node.NamespaceResolver ?? parentNode.NamespaceResolver)?.LookupPrefix(propertyName.NamespaceURI)))
				return;
			if (propertyName.NamespaceURI == "http://schemas.openxmlformats.org/markup-compatibility/2006" &&
				propertyName.LocalName == "Ignorable")
			{
				(parentNode.IgnorablePrefixes ?? (parentNode.IgnorablePrefixes = new List<string>())).AddRange(
					(node.Value as string).Split(','));
				return;
			}
			if (propertyName.LocalName != "MergedWith")
				return;
			SetPropertiesVisitor.SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node);
		}
コード例 #2
0
ファイル: XamlParser.cs プロジェクト: kvpt/Xamarin.Forms
        static IList <KeyValuePair <XmlName, INode> > ParseXamlAttributes(XmlReader reader, out IList <KeyValuePair <string, string> > xmlns)
        {
            Debug.Assert(reader.NodeType == XmlNodeType.Element);
            var attributes = new List <KeyValuePair <XmlName, INode> >();

            xmlns = new List <KeyValuePair <string, string> >();
            for (var i = 0; i < reader.AttributeCount; i++)
            {
                reader.MoveToAttribute(i);

                //skip xmlns
                if (reader.NamespaceURI == "http://www.w3.org/2000/xmlns/")
                {
                    xmlns.Add(new KeyValuePair <string, string>(reader.LocalName, reader.Value));
                    continue;
                }

                var namespaceUri = reader.NamespaceURI;
                if (reader.LocalName.Contains(".") && namespaceUri == "")
                {
                    namespaceUri = ((IXmlNamespaceResolver)reader).LookupNamespace("");
                }
                var propertyName = new XmlName(namespaceUri, reader.LocalName);

                object value = reader.Value;

                if (reader.NamespaceURI == X2006Uri)
                {
                    switch (reader.LocalName)
                    {
                    case "Key":
                        propertyName = XmlName.xKey;
                        break;

                    case "Name":
                        propertyName = XmlName.xName;
                        break;

                    case "Class":
                    case "FieldModifier":
                        continue;

                    default:
                        Debug.WriteLine("Unhandled attribute {0}", reader.Name);
                        continue;
                    }
                }

                if (reader.NamespaceURI == X2009Uri)
                {
                    switch (reader.LocalName)
                    {
                    case "Key":
                        propertyName = XmlName.xKey;
                        break;

                    case "Name":
                        propertyName = XmlName.xName;
                        break;

                    case "TypeArguments":
                        propertyName = XmlName.xTypeArguments;
                        value        = TypeArgumentsParser.ParseExpression((string)value, (IXmlNamespaceResolver)reader, (IXmlLineInfo)reader);
                        break;

                    case "DataType":
                        propertyName = XmlName.xDataType;
                        break;

                    case "Class":
                    case "FieldModifier":
                        continue;

                    case "FactoryMethod":
                        propertyName = XmlName.xFactoryMethod;
                        break;

                    case "Arguments":
                        propertyName = XmlName.xArguments;
                        break;

                    default:
                        Debug.WriteLine("Unhandled attribute {0}", reader.Name);
                        continue;
                    }
                }

                var propertyNode = GetValueNode(value, reader);
                attributes.Add(new KeyValuePair <XmlName, INode>(propertyName, propertyNode));
            }
            reader.MoveToElement();
            return(attributes);
        }
コード例 #3
0
ファイル: XamlParser.cs プロジェクト: xiaohszx/Xamarin.Forms
        static void ParseXamlElementFor(IElementNode node, XmlReader reader)
        {
            Debug.Assert(reader.NodeType == XmlNodeType.Element);

            var elementName = reader.Name;
            var isEmpty     = reader.IsEmptyElement;

            if (isEmpty)
            {
                return;
            }

            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                case XmlNodeType.EndElement:
                    Debug.Assert(reader.Name == elementName);                             //make sure we close the right element
                    return;

                case XmlNodeType.Element:
                    // 1. Property Element.
                    if (reader.Name.Contains("."))
                    {
                        XmlName name;
                        if (reader.Name.StartsWith(elementName + ".", StringComparison.Ordinal))
                        {
                            name = new XmlName(reader.NamespaceURI, reader.Name.Substring(elementName.Length + 1));
                        }
                        else                                 //Attached BP
                        {
                            name = new XmlName(reader.NamespaceURI, reader.LocalName);
                        }

                        if (node.Properties.ContainsKey(name))
                        {
                            throw new XamlParseException($"'{reader.Name}' is a duplicate property name.", (IXmlLineInfo)reader);
                        }

                        INode prop = null;
                        if (reader.IsEmptyElement)
                        {
                            Debug.WriteLine($"Unexpected empty element '<{reader.Name} />'", (IXmlLineInfo)reader);
                        }
                        else
                        {
                            prop = ReadNode(reader);
                        }

                        if (prop != null)
                        {
                            node.Properties.Add(name, prop);
                        }
                    }
                    // 2. Xaml2009 primitives, x:Arguments, ...
                    else if (reader.NamespaceURI == X2009Uri && reader.LocalName == "Arguments")
                    {
                        if (node.Properties.ContainsKey(XmlName.xArguments))
                        {
                            throw new XamlParseException($"'x:Arguments' is a duplicate directive name.", (IXmlLineInfo)reader);
                        }

                        var prop = ReadNode(reader);
                        if (prop != null)
                        {
                            node.Properties.Add(XmlName.xArguments, prop);
                        }
                    }
                    // 3. DataTemplate (should be handled by 4.)
                    else if (node.XmlType.NamespaceUri == XFUri &&
                             (node.XmlType.Name == "DataTemplate" || node.XmlType.Name == "ControlTemplate"))
                    {
                        if (node.Properties.ContainsKey(XmlName._CreateContent))
                        {
                            throw new XamlParseException($"Multiple child elements in {node.XmlType.Name}", (IXmlLineInfo)reader);
                        }

                        var prop = ReadNode(reader, true);
                        if (prop != null)
                        {
                            node.Properties.Add(XmlName._CreateContent, prop);
                        }
                    }
                    // 4. Implicit content, implicit collection, or collection syntax. Add to CollectionItems, resolve case later.
                    else
                    {
                        var item = ReadNode(reader, true);
                        if (item != null)
                        {
                            node.CollectionItems.Add(item);
                        }
                    }
                    break;

                case XmlNodeType.Whitespace:
                    break;

                case XmlNodeType.Text:
                case XmlNodeType.CDATA:
                    if (node.CollectionItems.Count == 1 && node.CollectionItems[0] is ValueNode)
                    {
                        ((ValueNode)node.CollectionItems[0]).Value += reader.Value.Trim();
                    }
                    else
                    {
                        node.CollectionItems.Add(new ValueNode(reader.Value.Trim(), (IXmlNamespaceResolver)reader));
                    }
                    break;

                default:
                    Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value);
                    break;
                }
            }
        }
コード例 #4
0
        public static void SetPropertyValue(object xamlelement, XmlName propertyName, object value, object rootElement, INode node, HydrationContext context, IXmlLineInfo lineInfo)
        {
            var       localName       = propertyName.LocalName;
            var       serviceProvider = new XamlServiceProvider(node, context);
            Exception xpe             = null;
            var       xKey            = node is IElementNode && ((IElementNode)node).Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)((IElementNode)node).Properties[XmlName.xKey]).Value as string : null;

            //If it's an attached BP, update elementType and propertyName
            var bpOwnerType = xamlelement.GetType();
            var attached    = GetRealNameAndType(ref bpOwnerType, propertyName.NamespaceURI, ref localName, context, lineInfo);
            var property    = GetBindableProperty(bpOwnerType, localName, lineInfo, false);

            //If the target is an event, connect
            if (xpe == null && TryConnectEvent(xamlelement, localName, attached, value, rootElement, lineInfo, out xpe))
            {
                return;
            }

            //If Value is DynamicResource and it's a BP, SetDynamicResource
            if (xpe == null && TrySetDynamicResource(xamlelement, property, value, lineInfo, out xpe))
            {
                return;
            }

            //If value is BindingBase, SetBinding
            if (xpe == null && TrySetBinding(xamlelement, property, localName, value, lineInfo, out xpe))
            {
                return;
            }

            //If it's a BindableProberty, SetValue
            if (xpe == null && TrySetValue(xamlelement, property, attached, value, lineInfo, serviceProvider, out xpe))
            {
                VisualDiagnostics.RegisterSourceInfo(value, null, ((IXmlLineInfo)node).LineNumber, ((IXmlLineInfo)node).LinePosition);
                VisualDiagnostics.SendVisualTreeChanged(xamlelement, value);
                return;
            }

            //If we can assign that value to a normal property, let's do it
            if (xpe == null && TrySetProperty(xamlelement, localName, value, lineInfo, serviceProvider, context, out xpe))
            {
                VisualDiagnostics.RegisterSourceInfo(value, null, ((IXmlLineInfo)node).LineNumber, ((IXmlLineInfo)node).LinePosition);
                VisualDiagnostics.SendVisualTreeChanged(xamlelement, value);
                return;
            }

            //If it's an already initialized property, add to it
            if (xpe == null && TryAddToProperty(xamlelement, propertyName, value, xKey, lineInfo, serviceProvider, context, out xpe))
            {
                VisualDiagnostics.RegisterSourceInfo(value, null, ((IXmlLineInfo)node).LineNumber, ((IXmlLineInfo)node).LinePosition);
                VisualDiagnostics.SendVisualTreeChanged(xamlelement, value);
                return;
            }

            xpe = xpe ?? new XamlParseException($"Cannot assign property \"{localName}\": Property does not exist, or is not assignable, or mismatching type between value and property", lineInfo);
            if (context.ExceptionHandler != null)
            {
                context.ExceptionHandler(xpe);
            }
            else
            {
                throw xpe;
            }
        }
コード例 #5
0
        public void Visit(ElementNode node, INode parentNode)
        {
            XmlName propertyName;

            if (TryGetPropertyName(node, parentNode, out propertyName) && propertyName == XmlName._CreateContent)
            {
                var s0 = Values[parentNode];
                if (s0 is ElementTemplate)
                {
                    SetTemplate(s0 as ElementTemplate, node);
                    return;
                }
            }

            var parentElement = parentNode as IElementNode;

            propertyName = XmlName.Empty;

            //Simplify ListNodes with single elements
            var pList = parentNode as ListNode;

            if (pList != null && pList.CollectionItems.Count == 1)
            {
                propertyName  = pList.XmlName;
                parentNode    = parentNode.Parent;
                parentElement = parentNode as IElementNode;
            }

            if (!Values.TryGetValue(node, out var value) && Context.ExceptionHandler != null)
            {
                return;
            }

            if (propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName))
            {
                if (Skips.Contains(propertyName))
                {
                    return;
                }
                if (parentElement.SkipProperties.Contains(propertyName))
                {
                    return;
                }

                if (!Values.TryGetValue(parentNode, out var source) && Context.ExceptionHandler != null)
                {
                    return;
                }
                ProvideValue(ref value, node, source, propertyName);
                SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
            }
            else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode)
            {
                if (!Values.TryGetValue(parentNode, out var source) && Context.ExceptionHandler != null)
                {
                    return;
                }
                ProvideValue(ref value, node, source, XmlName.Empty);
                string    contentProperty;
                Exception xpe  = null;
                var       xKey = node.Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)node.Properties[XmlName.xKey]).Value as string : null;

                //ResourceDictionary
                if (xpe == null && TryAddToResourceDictionary(source as ResourceDictionary, value, xKey, node, out xpe))
                {
                    return;
                }

                // Collection element, implicit content, or implicit collection element.
                if (xpe == null && typeof(IEnumerable).IsAssignableFrom(Context.Types[parentElement]) && Context.Types[parentElement].GetRuntimeMethods().Any(mi => mi.Name == "Add" && mi.GetParameters().Length == 1))
                {
                    var addMethod =
                        Context.Types[parentElement].GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);

                    addMethod.Invoke(source, new[] { value });
                    return;
                }
                if (xpe == null && (contentProperty = GetContentPropertyName(Context.Types[parentElement].GetTypeInfo())) != null)
                {
                    var name = new XmlName(node.NamespaceURI, contentProperty);
                    if (Skips.Contains(name))
                    {
                        return;
                    }
                    if (parentElement.SkipProperties.Contains(propertyName))
                    {
                        return;
                    }

                    SetPropertyValue(source, name, value, Context.RootElement, node, Context, node);
                    return;
                }
                xpe = xpe ?? new XamlParseException($"Can not set the content of {((IElementNode)parentNode).XmlType.Name} as it doesn't have a ContentPropertyAttribute", node);
                if (Context.ExceptionHandler != null)
                {
                    Context.ExceptionHandler(xpe);
                }
                else
                {
                    throw xpe;
                }
            }
            else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
            {
                if (!Values.TryGetValue(parentNode.Parent, out var source) && Context.ExceptionHandler != null)
                {
                    return;
                }
                ProvideValue(ref value, node, source, XmlName.Empty);
                var parentList = (ListNode)parentNode;
                if (Skips.Contains(parentList.XmlName))
                {
                    return;
                }
                Exception xpe  = null;
                var       xKey = node.Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)node.Properties[XmlName.xKey]).Value as string : null;

                var collection = GetPropertyValue(source, parentList.XmlName, Context, parentList, out _, out _) as IEnumerable;
                if (collection == null)
                {
                    xpe = new XamlParseException($"Property {parentList.XmlName.LocalName} is null or is not IEnumerable", node);
                }

                if (xpe == null && TryAddToResourceDictionary(collection as ResourceDictionary, value, xKey, node, out xpe))
                {
                    return;
                }

                MethodInfo addMethod;
                if (xpe == null && (addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) != null)
                {
                    addMethod.Invoke(collection, new[] { value });
                    return;
                }
                xpe = xpe ?? new XamlParseException($"Value of {parentList.XmlName.LocalName} does not have a Add() method", node);
                if (Context.ExceptionHandler != null)
                {
                    Context.ExceptionHandler(xpe);
                }
                else
                {
                    throw xpe;
                }
            }
        }
コード例 #6
0
        static void ParseXamlElementFor(IElementNode node, XmlReader reader)
        {
            Debug.Assert(reader.NodeType == XmlNodeType.Element);

            var elementName = reader.Name;
            var isEmpty     = reader.IsEmptyElement;

            if (isEmpty)
            {
                return;
            }

            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                case XmlNodeType.EndElement:
                    Debug.Assert(reader.Name == elementName);                             //make sure we close the right element
                    return;

                case XmlNodeType.Element:
                    // 1. Property Element.
                    if (reader.Name.Contains("."))
                    {
                        XmlName name;
                        if (reader.Name.StartsWith(elementName + ".", StringComparison.Ordinal))
                        {
                            name = new XmlName(reader.NamespaceURI, reader.Name.Substring(elementName.Length + 1));
                        }
                        else                                 //Attached DP
                        {
                            name = new XmlName(reader.NamespaceURI, reader.LocalName);
                        }

                        var prop = ReadNode(reader);
                        if (prop != null)
                        {
                            node.Properties.Add(name, prop);
                        }
                    }
                    // 2. Xaml2009 primitives, x:Arguments, ...
                    else if (reader.NamespaceURI == "http://schemas.microsoft.com/winfx/2009/xaml" && reader.LocalName == "Arguments")
                    {
                        var prop = ReadNode(reader);
                        if (prop != null)
                        {
                            node.Properties.Add(XmlName.xArguments, prop);
                        }
                    }
                    // 3. DataTemplate (should be handled by 4.)
                    else if (node.XmlType.NamespaceUri == "http://xamarin.com/schemas/2014/forms" &&
                             (node.XmlType.Name == "DataTemplate" || node.XmlType.Name == "ControlTemplate"))
                    {
                        var prop = ReadNode(reader, true);
                        if (prop != null)
                        {
                            node.Properties.Add(XmlName._CreateContent, prop);
                        }
                    }
                    // 4. Implicit content, implicit collection, or collection syntax. Add to CollectionItems, resolve case later.
                    else
                    {
                        var item = ReadNode(reader, true);
                        if (item != null)
                        {
                            node.CollectionItems.Add(item);
                        }
                    }
                    break;

                case XmlNodeType.Whitespace:
                    break;

                case XmlNodeType.Text:
                case XmlNodeType.CDATA:
                    if (node.CollectionItems.Count == 1 && node.CollectionItems[0] is ValueNode)
                    {
                        ((ValueNode)node.CollectionItems[0]).Value += reader.Value.Trim();
                    }
                    else
                    {
                        node.CollectionItems.Add(new ValueNode(reader.Value.Trim(), (IXmlNamespaceResolver)reader));
                    }
                    break;

                default:
                    Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value);
                    break;
                }
            }
        }
コード例 #7
0
        public void Visit(ElementNode node, INode parentNode)
        {
            XmlName propertyName;

            if (TryGetPropertyName(node, parentNode, out propertyName) && propertyName == XmlName._CreateContent)
            {
                var s0 = Values[parentNode];
                if (s0 is ElementTemplate)
                {
                    SetTemplate(s0 as ElementTemplate, node);
                    return;
                }
            }

            var parentElement = parentNode as IElementNode;

            propertyName = XmlName.Empty;

            //Simplify ListNodes with single elements
            var pList = parentNode as ListNode;

            if (pList != null && pList.CollectionItems.Count == 1)
            {
                propertyName  = pList.XmlName;
                parentNode    = parentNode.Parent;
                parentElement = parentNode as IElementNode;
            }

            var value = Values[node];

            if (propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName))
            {
                if (Skips.Contains(propertyName))
                {
                    return;
                }
                if (parentElement.SkipProperties.Contains(propertyName))
                {
                    return;
                }

                var source = Values[parentNode];
                ProvideValue(ref value, node, source, propertyName);
                SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
            }
            else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode)
            {
                var source = Values[parentNode];
                ProvideValue(ref value, node, source, XmlName.Empty);
                string contentProperty;

                // Implicit Style Resource in a ResourceDictionary
                if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[parentElement]) && value is Style &&
                    !node.Properties.ContainsKey(XmlName.xKey))
                {
                    ((ResourceDictionary)source).Add(value as Style);
                }
                // Resource without a x:Key in a ResourceDictionary
                else if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[parentElement]) && !node.Properties.ContainsKey(XmlName.xKey))
                {
                    throw new XamlParseException("resources in ResourceDictionary require a x:Key attribute", node);
                }
                // Resource in a ResourceDictionary
                else if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[parentElement]) && node.Properties.ContainsKey(XmlName.xKey))
                {
                    ((ResourceDictionary)source).Add((string)(((ValueNode)node.Properties[XmlName.xKey]).Value), value);
                }
                // Collection element, implicit content, or implicit collection element.
                else if (typeof(IEnumerable).IsAssignableFrom(Context.Types[parentElement]) && Context.Types[parentElement].GetRuntimeMethods().Any(mi => mi.Name == "Add" && mi.GetParameters().Length == 1))
                {
                    if (!(typeof(ResourceDictionary).IsAssignableFrom(Context.Types[parentElement])))
                    {
                        var addMethod =
                            Context.Types[parentElement].GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
                        addMethod.Invoke(source, new[] { value });
                    }
                }
                else if ((contentProperty = GetContentPropertyName(Context.Types[parentElement].GetTypeInfo())) != null)
                {
                    var name = new XmlName(node.NamespaceURI, contentProperty);
                    if (Skips.Contains(name))
                    {
                        return;
                    }
                    if (parentElement.SkipProperties.Contains(propertyName))
                    {
                        return;
                    }

                    SetPropertyValue(source, name, value, Context.RootElement, node, Context, node);
                }
                else
                {
                    throw new XamlParseException($"Can not set the content of {((IElementNode)parentNode).XmlType.Name} as it doesn't have a ContentPropertyAttribute", node);
                }
            }
            else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
            {
                var source = Values[parentNode.Parent];
                ProvideValue(ref value, node, source, XmlName.Empty);

                var parentList = (ListNode)parentNode;

                if (Skips.Contains(parentList.XmlName))
                {
                    return;
                }

                var elementType = source.GetType();
                var localname   = parentList.XmlName.LocalName;

                GetRealNameAndType(ref elementType, parentList.XmlName.NamespaceURI, ref localname, Context, node);

                PropertyInfo propertyInfo = null;
                try
                {
                    propertyInfo = elementType.GetRuntimeProperty(localname);
                }
                catch (AmbiguousMatchException)
                {
                    // Get most derived instance of property
                    foreach (var property in elementType.GetRuntimeProperties().Where(prop => prop.Name == localname))
                    {
                        if (propertyInfo == null || propertyInfo.DeclaringType.IsAssignableFrom(property.DeclaringType))
                        {
                            propertyInfo = property;
                        }
                    }
                }
                if (propertyInfo == null)
                {
                    throw new XamlParseException(Format("Property {0} not found", localname), node);
                }
                MethodInfo getter;
                if (!propertyInfo.CanRead || (getter = propertyInfo.GetMethod) == null)
                {
                    throw new XamlParseException(Format("Property {0} does not have an accessible getter", localname), node);
                }
                IEnumerable collection;
                if ((collection = getter.Invoke(source, new object[] { }) as IEnumerable) == null)
                {
                    throw new XamlParseException(Format("Property {0} is null or is not IEnumerable", localname), node);
                }
                MethodInfo addMethod;
                if (
                    (addMethod =
                         collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) == null)
                {
                    throw new XamlParseException(Format("Value of {0} does not have a Add() method", localname), node);
                }

                addMethod.Invoke(collection, new[] { Values[node] });
            }
        }
コード例 #8
0
        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(addMethod.GetParameters()[0].ParameterType, (Func <TypeConverter>)null, serviceProvider) });
                    return;
                }
            }

            if (context.DoNotThrowOnExceptions)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message);
            }
            else
            {
                throw exception;
            }
        }
コード例 #9
0
        public void Visit(ElementNode node, INode parentNode)
        {
            var value           = Values[node];
            var parentElement   = parentNode as IElementNode;
            var markupExtension = value as IMarkupExtension;
            var valueProvider   = value as IValueProvider;

            if (markupExtension != null)
            {
                var serviceProvider = new XamlServiceProvider(node, Context);
                value = markupExtension.ProvideValue(serviceProvider);
            }

            if (valueProvider != null)
            {
                var serviceProvider = new XamlServiceProvider(node, Context);
                value = valueProvider.ProvideValue(serviceProvider);
            }

            XmlName propertyName = XmlName.Empty;

            //Simplify ListNodes with single elements
            var pList = parentNode as ListNode;

            if (pList != null && pList.CollectionItems.Count == 1)
            {
                propertyName  = pList.XmlName;
                parentNode    = parentNode.Parent;
                parentElement = parentNode as IElementNode;
            }

            if (propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName))
            {
                if (Skips.Contains(propertyName))
                {
                    return;
                }
                if (parentElement.SkipProperties.Contains(propertyName))
                {
                    return;
                }

                var source = Values [parentNode];

                if (propertyName == XmlName._CreateContent && source is ElementTemplate)
                {
                    SetTemplate(source as ElementTemplate, node);
                }
                else
                {
                    SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
                }
            }
            else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode)
            {
                // Collection element, implicit content, or implicit collection element.
                string contentProperty;
                if (typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(Context.Types[parentElement].GetTypeInfo()))
                {
                    var source = Values[parentNode];
                    if (!(typeof(ResourceDictionary).IsAssignableFrom(Context.Types[parentElement])))
                    {
                        var addMethod =
                            Context.Types[parentElement].GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
                        addMethod.Invoke(source, new[] { value });
                    }
                }
                else if ((contentProperty = GetContentPropertyName(Context.Types[parentElement].GetTypeInfo())) != null)
                {
                    var name = new XmlName(node.NamespaceURI, contentProperty);
                    if (Skips.Contains(name))
                    {
                        return;
                    }
                    if (parentElement.SkipProperties.Contains(propertyName))
                    {
                        return;
                    }

                    var source = Values[parentNode];
                    SetPropertyValue(source, name, value, Context.RootElement, node, Context, node);
                }
            }
            else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
            {
                var parentList = (ListNode)parentNode;
                var source     = Values[parentNode.Parent];

                if (Skips.Contains(parentList.XmlName))
                {
                    return;
                }

                var elementType = source.GetType();
                var localname   = parentList.XmlName.LocalName;

                GetRealNameAndType(ref elementType, parentList.XmlName.NamespaceURI, ref localname, Context, node);

                PropertyInfo propertyInfo = null;
                try
                {
                    propertyInfo = elementType.GetRuntimeProperty(localname);
                }
                catch (AmbiguousMatchException)
                {
                    // Get most derived instance of property
                    foreach (var property in elementType.GetRuntimeProperties().Where(prop => prop.Name == localname))
                    {
                        if (propertyInfo == null || propertyInfo.DeclaringType.IsAssignableFrom(property.DeclaringType))
                        {
                            propertyInfo = property;
                        }
                    }
                }
                if (propertyInfo == null)
                {
                    throw new XamlParseException(string.Format("Property {0} not found", localname), node);
                }
                MethodInfo getter;
                if (!propertyInfo.CanRead || (getter = propertyInfo.GetMethod) == null)
                {
                    throw new XamlParseException(string.Format("Property {0} does not have an accessible getter", localname), node);
                }
                IEnumerable collection;
                if ((collection = getter.Invoke(source, new object[] { }) as IEnumerable) == null)
                {
                    throw new XamlParseException(string.Format("Property {0} is null or is not IEnumerable", localname), node);
                }
                MethodInfo addMethod;
                if (
                    (addMethod =
                         collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) == null)
                {
                    throw new XamlParseException(string.Format("Value of {0} does not have a Add() method", localname), node);
                }

                addMethod.Invoke(collection, new[] { Values[node] });
            }
        }
コード例 #10
0
        //Used by HotReload, do not change signature
        public static bool TrySetPropertyValue(object element, XmlName propertyName, string xKey, object value, object rootElement, IXmlLineInfo lineInfo, IServiceProvider serviceProvider, out Exception xpe)
        {
            var localName = propertyName.LocalName;

            xpe = null;

            void registerSourceInfo(object target, string path)
            {
                var assemblyName = rootElement.GetType().GetTypeInfo().Assembly?.GetName().Name;

                if (lineInfo != null)
                {
                    VisualDiagnostics.RegisterSourceInfo(target, new Uri($"{path};assembly={assemblyName}", UriKind.Relative), lineInfo.LineNumber, lineInfo.LinePosition);
                }
            }

            //If it's an attached BP, update elementType and propertyName
            var bpOwnerType = element.GetType();
            var attached    = GetRealNameAndType(ref bpOwnerType, propertyName.NamespaceURI, ref localName, rootElement, lineInfo);
            var property    = GetBindableProperty(bpOwnerType, localName, lineInfo, false);

            //If the target is an event, connect
            if (xpe == null && TryConnectEvent(element, localName, attached, value, rootElement, lineInfo, out xpe))
            {
                return(true);
            }

            //If Value is DynamicResource and it's a BP, SetDynamicResource
            if (xpe == null && TrySetDynamicResource(element, property, value, lineInfo, out xpe))
            {
                return(true);
            }

            //If value is BindingBase, SetBinding
            if (xpe == null && TrySetBinding(element, property, localName, value, lineInfo, out var binding, out xpe))
            {
                if (binding != null && XamlFilePathAttribute.GetFilePathForObject(rootElement) is string path)
                {
                    registerSourceInfo(binding, path);
                }
                return(true);
            }

            //If it's a BindableProberty, SetValue
            if (xpe == null && TrySetValue(element, property, attached, value, lineInfo, serviceProvider, out xpe))
            {
                if (value != null && !value.GetType().GetTypeInfo().IsValueType&& XamlFilePathAttribute.GetFilePathForObject(rootElement) is string path)
                {
                    registerSourceInfo(value, path);
                }
                return(true);
            }

            //If we can assign that value to a normal property, let's do it
            if (xpe == null && TrySetProperty(element, localName, value, lineInfo, serviceProvider, rootElement, out xpe))
            {
                if (value != null && !value.GetType().GetTypeInfo().IsValueType&& XamlFilePathAttribute.GetFilePathForObject(rootElement) is string path)
                {
                    registerSourceInfo(value, path);
                }
                return(true);
            }

            //If it's an already initialized property, add to it
            if (xpe == null && TryAddToProperty(element, propertyName, value, xKey, lineInfo, serviceProvider, rootElement, out xpe))
            {
                if (value != null && !value.GetType().GetTypeInfo().IsValueType&& XamlFilePathAttribute.GetFilePathForObject(rootElement) is string path)
                {
                    registerSourceInfo(value, path);
                }
                return(true);
            }

            xpe = xpe ?? new XamlParseException($"Cannot assign property \"{localName}\": Property does not exist, or is not assignable, or mismatching type between value and property", lineInfo);
            return(false);
        }