Class with static methods to parse XAML files and output a XamlDocument.
Ejemplo n.º 1
0
        public static XamlObject Parse(string text, XamlObject parent, XmlAttribute attribute)
        {
            var tokens = MarkupExtensionTokenizer.Tokenize(text);

            if (tokens.Count < 3 ||
                tokens[0].Kind != MarkupExtensionTokenKind.OpenBrace ||
                tokens[1].Kind != MarkupExtensionTokenKind.TypeName ||
                tokens[tokens.Count - 1].Kind != MarkupExtensionTokenKind.CloseBrace)
            {
                throw new XamlMarkupExtensionParseException("Invalid markup extension");
            }

            var typeResolver = parent.ServiceProvider.Resolver;

            string typeName      = tokens[1].Value;
            Type   extensionType = typeResolver.Resolve(typeName + "Extension");

            if (extensionType == null)
            {
                extensionType = typeResolver.Resolve(typeName);
            }
            if (extensionType == null || !typeof(MarkupExtension).IsAssignableFrom(extensionType))
            {
                throw new XamlMarkupExtensionParseException("Unknown markup extension " + typeName + "Extension");
            }

            List <string> positionalArgs = new List <string>();
            List <KeyValuePair <string, string> > namedArgs = new List <KeyValuePair <string, string> >();

            for (int i = 2; i < tokens.Count - 1; i++)
            {
                if (tokens[i].Kind == MarkupExtensionTokenKind.String)
                {
                    positionalArgs.Add(tokens[i].Value);
                }
                else if (tokens[i].Kind == MarkupExtensionTokenKind.Membername)
                {
                    if (tokens[i + 1].Kind != MarkupExtensionTokenKind.Equals ||
                        tokens[i + 2].Kind != MarkupExtensionTokenKind.String)
                    {
                        throw new XamlMarkupExtensionParseException("Invalid markup extension");
                    }
                    namedArgs.Add(new KeyValuePair <string, string>(tokens[i].Value, tokens[i + 2].Value));
                    i += 2;
                }
            }

            // Find the constructor with positionalArgs.Count arguments
            var ctors = extensionType.GetConstructors().Where(c => c.GetParameters().Length == positionalArgs.Count).ToList();

            if (ctors.Count < 1)
            {
                throw new XamlMarkupExtensionParseException("No constructor for " +
                                                            extensionType.FullName + " found that takes " + positionalArgs.Count + " arguments");
            }
            if (ctors.Count > 1)
            {
                Debug.WriteLine("Multiple constructors for " +
                                extensionType.FullName + " found that take " + positionalArgs.Count + " arguments");
            }

            var  ctor                = ctors[0];
            var  defaultCtor         = extensionType.GetConstructor(Type.EmptyTypes);
            bool mappingToProperties = defaultCtor != null;
            List <PropertyInfo> map  = new List <PropertyInfo>();

            if (mappingToProperties)
            {
                foreach (var param in ctor.GetParameters())
                {
                    var prop = extensionType.GetProperty(param.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                    if (prop == null)
                    {
                        mappingToProperties = false;
                        break;
                    }
                    map.Add(prop);
                }
            }

            object instance;

            if (mappingToProperties)
            {
                instance = defaultCtor.Invoke(null);
            }
            else
            {
                var ctorParamsInfo = ctor.GetParameters();
                var ctorParams     = new object[ctorParamsInfo.Length];
                for (int i = 0; i < ctorParams.Length; i++)
                {
                    var paramType = ctorParamsInfo[i].ParameterType;
                    ctorParams[i] = XamlParser.CreateObjectFromAttributeText(positionalArgs[i], paramType, parent);
                }
                instance = ctor.Invoke(ctorParams);
                //TODO
                //XamlObject.ConstructorArgsProperty - args collection
                //Reinvoke ctor when needed
            }

            XamlObject result = parent.OwnerDocument.CreateObject(instance);

            if (attribute != null)
            {
                result.XmlAttribute = attribute;
            }
            result.ParentObject = parent;

            if (mappingToProperties)
            {
                for (int i = 0; i < positionalArgs.Count; i++)
                {
                    var a = parent.OwnerDocument.XmlDocument.CreateAttribute(map[i].Name);
                    a.Value = positionalArgs[i];
                    XamlParser.ParseObjectAttribute(result, a, false);
                }
            }
            foreach (var pair in namedArgs)
            {
                var a = parent.OwnerDocument.XmlDocument.CreateAttribute(pair.Key);
                a.Value = pair.Value;
                XamlParser.ParseObjectAttribute(result, a, false);
            }
            return(result);
        }