示例#1
0
        protected object ParseValue(string str)
        {
            if (str.StartsWith("{}")) // {} = escape sequence
            {
                return(str.Substring(2));
            }
            if (!str.StartsWith("{"))
            {
                // Normal value, no markup extension
                return(str);
            }

            // Object/markup extension instantiation in attribute value syntax
            if (!str.EndsWith("}"))
            {
                throw new XamlParserException("Object instantiation expression '{0}' must be terminated by a '}}' character", str);
            }
            string             expr           = str.Substring(1, str.Length - 2).Trim(); // Extract the expression
            ElementContextInfo elementContext = _elementContextStack.PushElementContext(expr);

            try
            {
                // Step 1: Process namespace declarations (doesn't apply here)
                string extensionName;
                IList <KeyValuePair <string, string> > parameters;
                bool namedParams;
                AttributeValueInstantiationParser.ParseInstantiationExpression(
                    expr, out extensionName, out parameters, out namedParams);
                string namespaceURI;
                LookupNamespace(extensionName, out extensionName, out namespaceURI);
                IInitializable initializable = null;
                if (namedParams)
                {
                    // Parameters given in a Name=Value syntax
                    // Step 2: Instantiate the element
                    elementContext.Instance = GetNamespaceHandler(namespaceURI).InstantiateElement(
                        this, extensionName, new List <object>()); // Invoke default constructor
                    initializable = elementContext.Instance as IInitializable;
                    if (initializable != null)
                    {
                        initializable.StartInitialization(this);
                    }

                    // Step 4: Members and events in attribute syntax

                    // We only process the given parameters and assign their values to the
                    // target members. Property value inheritance, for example the
                    // inheritance of a "Context" member for bindings, has to be
                    // implemented on the visual's element class hierarchy.
                    foreach (KeyValuePair <string, string> parameter in parameters) // Assign value to each specified member
                    {
                        string          memberName = parameter.Key;
                        IDataDescriptor dd;
                        if (ReflectionHelper.FindMemberDescriptor(elementContext.Instance, memberName, out dd))
                        {
                            object paramVal = ParseValue(parameter.Value);
                            HandleMemberAssignment(dd, paramVal);
                            // Step 4: Name registration
                            if (memberName == "Name")
                            {
                                string value = Convert(paramVal, typeof(string)) as string;
                                RegisterName(value, elementContext.Instance);
                            }
                        }
                        else
                        {
                            throw new XamlBindingException(
                                      "XAML parser: Member '{0}' was not found on element type '{1}'",
                                      memberName, elementContext.Instance.GetType().Name);
                        }
                    }
                }
                else
                {
                    // Parameters given as constructor parameters
                    // Step 2: Instantiate the element
                    IList <object> flatParams = new List <object>();
                    foreach (string param in AttributeValueInstantiationParser.ExtractParameterValues(parameters))
                    {
                        object value = ParseValue(param);
                        IEvaluableMarkupExtension evaluableMarkupExtension = value as IEvaluableMarkupExtension;
                        if (evaluableMarkupExtension != null)
                        {
                            evaluableMarkupExtension.Initialize(this);
                            if (!evaluableMarkupExtension.Evaluate(out value))
                            {
                                throw new XamlParserException("Could not evaluate markup extension '{0}'", evaluableMarkupExtension);
                            }
                        }
                        flatParams.Add(value);
                    }
                    elementContext.Instance = GetNamespaceHandler(namespaceURI).InstantiateElement(this, extensionName, flatParams);
                    initializable           = elementContext.Instance as IInitializable;
                    if (initializable != null)
                    {
                        initializable.StartInitialization(this);
                    }

                    // Step 4: Members and events in attribute syntax (doesn't apply here)
                }
                // Step 5: Member values in member element syntax (doesn't apply here)
                // Step 6: Handle child elements (doesn't apply here)
                // Step 7: Initialize
                if (initializable != null)
                {
                    initializable.FinishInitialization(this);
                }

                return(elementContext.Instance);
            }
            finally
            {
                _elementContextStack.PopElementContext();
            }
        }
示例#2
0
        /// <summary>
        /// Instantiates the specified XML element located under the current element context
        /// in the <see cref="_elementContextStack"/> and sets the resulting element up.
        /// </summary>
        /// <remarks>
        /// Before calling this, the parent element, which is the current top element
        /// on the element context stack, has to be instantiated and its namespaces
        /// have to be imported. In the current implementation, its attributes will
        /// also already be processed.
        /// When this method returns, the returned visual element is completely set up,
        /// this means, it was instantiated, its members and events were processed
        /// and its content member was assigned. The processing of the complete
        /// structure under <paramref name="currentElement"/> has finished.
        /// </remarks>
        /// <param name="currentElement">The XML element under the
        /// current element on the element's context stack, which has to be
        /// instantiated and set up.</param>
        /// <param name="key">Will be set if an <c>x:Key</c> attribute was set on the
        /// element to parse.</param>
        /// <returns>Instantiated XAML visual element corresponding to the
        /// specified <paramref name="currentElement"/>.</returns>
        protected object Instantiate(XmlElement currentElement, out object key)
        {
            ElementContextInfo elementContext = _elementContextStack.PushElementContext(currentElement);

            try
            {
                string name = null;
                key = null;

                IList <XmlAttribute> remainingAttributes = new List <XmlAttribute>(currentElement.Attributes.Count);
                // Step 1: Process namespace declarations (to be done first)
                foreach (XmlAttribute attr in currentElement.Attributes)
                {
                    // We have to sort out namespace declarations.
                    // For both declarations xmlns="..." and xmlns:xx="...", the parser returns the
                    // namespace URI "http://www.w3.org/2000/xmlns/" (static constant
                    // <see cref="XMLNS_NS_URI"/>) for the attribute, so we check for this
                    // namespace URI. The value of the attribute (for example
                    // "http://schemas.microsoft.com/winfx/2006/xaml") is the URI
                    // of the namespace to be imported.
                    if (attr.NamespaceURI == XMLNS_NS_URI)
                    {
                        string            importNamespaceURI = attr.Value;
                        INamespaceHandler handler;
                        if (importNamespaceURI == XamlNamespaceHandler.XAML_NS_URI)
                        {
                            // Implicit namespace: Use default x:-handler
                            handler = new XamlNamespaceHandler();
                        }
                        else if (importNamespaceURI.StartsWith("clr-namespace:"))
                        {
                            handler = ImportClrNamespace(importNamespaceURI);
                        }
                        else
                        {
                            handler = _importCustomNamespace(this, importNamespaceURI);
                        }
                        _elementContextStack.RegisterNamespaceHandler(importNamespaceURI, handler);
                    }
                    else
                    {
                        // Store other attributes so we don't need to sort out the namespace declarations in step 3
                        remainingAttributes.Add(attr);
                    }
                }

                // Step 2: Instantiate the element
                elementContext.Instance = GetNamespaceHandler(currentElement.NamespaceURI).
                                          InstantiateElement(this, currentElement.LocalName, new List <object>());
                IInitializable initializable = elementContext.Instance as IInitializable;
                if (initializable != null)
                {
                    initializable.StartInitialization(this);
                }

                // Step 3: Name registration and check for x:Key (to be done before child objects are built)
                foreach (XmlAttribute attr in remainingAttributes)
                {
                    CheckNameOrKey(attr, ref name, ref key);
                }
                foreach (XmlNode node in currentElement.ChildNodes)
                {
                    CheckNameOrKey(node, ref name, ref key);
                }
                if (name != null)
                {
                    RegisterName(name, elementContext.Instance);
                }

                // Step 4: Members and events in attribute syntax
                foreach (XmlAttribute attr in remainingAttributes)
                {
                    HandleMemberOrEventAssignment(attr);
                }

                // Step 5: Member values in member element syntax
                foreach (XmlNode node in currentElement.ChildNodes)
                {
                    // Hint: We do not enforce, that object elements, which are used to fill the
                    // XAML content member within an object element, must be contiguous
                    if (node is XmlElement && node.LocalName.IndexOf('.') != -1) // "." is used as indicator that we have a member declaration
                    {
                        // Check XML attributes on member element - only x:Uid is permitted
                        foreach (XmlAttribute attr in node.Attributes)
                        {
                            if (attr.NamespaceURI != XamlNamespaceHandler.XAML_NS_URI || attr.LocalName != "Uid")
                            {
                                throw new XamlParserException("No attributes are allowed on member elements except x:Uid");
                            }
                            // TODO: Handle x:Uid markup extension
                        }
                        HandleMemberOrEventAssignment(node);
                    }
                }

                // Step 6: Handle child elements
                if (elementContext.Instance is INativeXamlObject)
                { // Implementors of INativeXamlObject will handle their XAML child elements theirselves
                    ((INativeXamlObject)elementContext.Instance).HandleChildren(this, currentElement);
                }
                else
                { // Content member value/Children handled by this XAML parser
                    object value = ParseValue(currentElement);
                    if (value != null)
                    {
                        IDataDescriptor dd;
                        if (elementContext.Instance is IContentEnabled &&
                            ((IContentEnabled)elementContext.Instance).FindContentProperty(out dd))
                        {
                            HandleMemberAssignment(dd, value);
                        }
                        else if (ReflectionHelper.CheckHandleCollectionAssignment(elementContext.Instance, value))
                        {
                        }
                        else
                        {
                            throw new XamlBindingException("Visual element '{0}' doesn't support adding children",
                                                           currentElement.Name);
                        }
                    }
                }

                // Step 7: Initialize
                if (initializable != null)
                {
                    initializable.FinishInitialization(this);
                }

                return(elementContext.Instance);
            }
            finally
            {
                _elementContextStack.PopElementContext();
            }
        }