Esempio n. 1
0
        /// <summary>
        /// Parses a property index expression in the form <c>(sys:Int32)42,(sys:Int32)24,SampleString</c>,
        /// where sys is mapped to the system namespace.
        /// Inside indexers, multiple indexer parameters are separated by commas (,).
        /// The type of each parameter can be specified with parentheses.
        /// </summary>
        /// <param name="context">The current parser context.</param>
        /// <param name="expression">The index expression to parse. The index expression is
        /// the expression between the <c>[</c> and <c>]</c> characters, for example in
        /// <c>PropertyName[10,20]</c>, the index expression is <c>10,20</c>.</param>
        /// <returns>Object array containing index parameters from the
        /// <paramref name="expression"/>.</returns>
        public static object[] ParseIndexExpression(IParserContext context, string expression)
        {
            IList <object> indices = new List <object>();

            string[] indexStrings = expression.Split(new char[] { ',' });
            foreach (string s in indexStrings)
            {
                string valStr       = s;
                Type   explicitType = null;
                if (valStr.StartsWith("("))
                { // Explicit type is given
                    int i = valStr.IndexOf(')');
                    explicitType = ParseType(context, s.Substring(1, i - 1));
                    valStr       = valStr.Substring(i + 1);
                }
                object indexResult = valStr;
                if (explicitType != null)
                {
                    if (!TypeConverter.Convert(indexResult, explicitType, out indexResult))
                    {
                        throw new XamlParserException("Could not convert '{0}' to type '{1}'", indexResult, explicitType.Name);
                    }
                }
                indices.Add(indexResult);
            }
            object[] result = new object[indexStrings.Length];
            indices.CopyTo(result, 0);
            return(result);
        }
        /// <summary>
        /// Convertes all objects in the specified <paramref name="objects"/> array to the specified
        /// <paramref name="types"/>. The number of types may be greater than the number of objects;
        /// this supports type conversion for both mandatory and optional parameters.
        /// </summary>
        /// <param name="objects">The array of objects to be type-converted.</param>
        /// <param name="types">Desired types the objects should be converted to.
        /// Indices in the <paramref name="types"/> array correspond to indices
        /// of the <paramref name="objects"/> array. The <paramref name="types"/>
        /// array may contain more elements than the <paramref name="objects"/> array.</param>
        /// <param name="convertedObjects">Returns the array of converted objects.
        /// The size of this returned array is the same as the size of the
        /// <paramref name="objects"/> array.</param>
        /// <returns><c>true</c>, if the conversion was successful for all objects
        /// in the input array, else <c>false</c>.</returns>
        /// <exception cref="XamlBindingException">If the number of objects given is greater than
        /// the number of types given.</exception>
        public static bool ConvertTypes(IEnumerable <object> objects, Type[] types,
                                        out object[] convertedObjects)
        {
            // Convert objects to index types
            convertedObjects = null;
            List <object> result  = new List <object>(types.Length);
            int           current = 0;

            foreach (object obj in objects)
            {
                if (current >= types.Length)
                {
                    return(false);
                }
                object converted;
                if (!TypeConverter.Convert(obj, types[current], out converted))
                {
                    return(false);
                }
                result.Add(converted);
                current++;
            }
            convertedObjects = result.ToArray();
            return(true);
        }
Esempio n. 3
0
        /// <summary>
        /// Checks the existance of a <c>Name</c> and the <c>x:Name</c> and <c>x:Key</c>
        /// pseudo member nodes in both attribute syntax and member element syntax.
        /// Other nodes from the <c>x:</c> namespace will be rejected by throwing
        /// an exception.
        /// Names given by a <c>x:Name</c> will be automatically assigned to the
        /// current element's "Name" attribute, if it is present.
        /// Except <c>Name</c>, this method ignores "normal" members and events,
        /// which will be handled in method
        /// <see cref="HandleMemberOrEventAssignment"/>.
        /// </summary>
        /// <remarks>
        /// Implementation node: We separate this method from method
        /// <see cref="HandleMemberOrEventAssignment"/>
        /// because both methods handle attributes of different scopes. The <c>x:</c>
        /// attributes are attributes which affect the outside world, as they associate
        /// a name or key to the current element in the outer scope. In contrast to
        /// this, "Normal" members are set on the current element and do not affect
        /// the outer scope.
        /// </remarks>
        /// <param name="memberDeclarationNode">Node containing a <c>x:</c> attribute
        /// for the current element. This node can either
        /// be an <see cref="XmlAttribute"/> node (for attribute syntax) or an
        /// <see cref="XmlElement"/> node (for member element syntax).
        /// This method ignores "normal" member and event attributes.</param>
        /// <param name="name">Will be set if the node to handle is an <c>x:Name</c>.</param>
        /// <param name="key">Will be set if the node to handle is an <c>x:Key</c>.</param>
        protected void CheckNameOrKey(XmlNode memberDeclarationNode, ref string name, ref object key)
        {
            ElementContextInfo elementContext = _elementContextStack.CurrentElementContext;

            // Name
            if ((memberDeclarationNode.Prefix == string.Empty ||
                 memberDeclarationNode.NamespaceURI == elementContext.Element.NamespaceURI) &&
                memberDeclarationNode.LocalName == "Name")
            {
                name = Convert(ParseValue(memberDeclarationNode), typeof(string)) as string;
                return;
            }
            if (memberDeclarationNode.NamespaceURI != XamlNamespaceHandler.XAML_NS_URI)
            {
                // Ignore other attributes not located in the x: namespace
                return;
            }
            // x: attributes
            if (memberDeclarationNode.LocalName == "Name") // x:Name
            {                                              // x:Name
                if (name == null)
                {
                    object value = ParseValue(memberDeclarationNode);
                    name = TypeConverter.Convert(value, typeof(string)) as string;
                    // Assign name to "Name" member, if one exists
                    IDataDescriptor dd;
                    if (ReflectionHelper.FindMemberDescriptor(
                            elementContext.Instance, "Name", out dd))
                    {
                        // Member assignment
                        HandleMemberAssignment(dd, value);
                    }
                }
                else
                {
                    throw new XamlBindingException("Attribute '{0}' was specified multiple times", memberDeclarationNode.Name);
                }
            }
            else if (memberDeclarationNode.LocalName == "Key")
            { // x:Key
                object value = ParseValue(memberDeclarationNode);
                if (key == null)
                {
                    key = value;
                }
                else
                {
                    throw new XamlBindingException("Attribute '{0}' was specified multiple times", memberDeclarationNode.Name);
                }
            }
            else if (memberDeclarationNode is XmlAttribute)
            {
                // TODO: Is it correct to reject all usages of x:Attr attributes except x:Key and x:Name?
                throw new XamlParserException("Attribute '{0}' cannot be used here", memberDeclarationNode.Name);
            }
        }
Esempio n. 4
0
        protected object Convert(object source)
        {
            if (!_negate)
            {
                return(source);
            }
            // If negate, we need to convert to bool
            object value = false;

            if (source != null)
            {
                value = source;
                if (!TypeConverter.Convert(value, typeof(bool), out value))
                {
                    return(value != null);
                }
            }
            return(!(bool)value);
        }
Esempio n. 5
0
 protected static object Convert(object val, Type targetType)
 {
     try
     {
         object result;
         if (TypeConverter.Convert(val, targetType, out result))
         {
             return(result);
         }
         throw new XamlBindingException("Could not convert object '{0}' to type '{1}'", val, targetType.Name);
     }
     catch (Exception e)
     {
         if (e is XamlBindingException)
         {
             throw;
         }
         throw new XamlBindingException("Could not convert object '{0}' to type '{1}'", val, targetType.Name);
     }
 }
        /// <summary>
        /// Checks if the specified <paramref name="maybeCollectionTarget"/> parameter
        /// is an object which is not null and which supports any collection element adding
        /// facility. The specified <paramref name="value"/> will then be assigned to the
        /// collection.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method will be needed in two cases:
        /// <list type="number">
        /// <item>A property should be assigned, which has a collection-like type. These properties
        /// won't be assigned directly but they are expected to have a not-null collection value.
        /// Adding children to them will cause calling some "Add" method on the existing instance.</item>
        /// <item>Child elements should be assigned to an object which doesn't support
        /// the <see cref="IContentEnabled"/> interface. So if there is no content property,
        /// the parser tries to add children directly to the object, if it is supported.</item>
        /// </list>
        /// In both cases, there is already an existing (collection-like) instance, to that the
        /// specified <paramref name="value"/> should be assigned, so this method has no
        /// need to create the collection itself.
        /// </para>
        /// <para>
        /// If this method cannot handle the specified target object
        /// <paramref name="maybeCollectionTarget"/>, or if this parameter is <c>null</c>,
        /// it will return <c>false</c> to signal that it couldn't do the assignment.
        /// </para>
        /// </remarks>
        /// <param name="maybeCollectionTarget">Parameter holding an instance which may be
        /// a collection type to add the <paramref name="value"/> to. May also be <c>null</c>,
        /// which will result in a return value of <c>false</c>.</param>
        /// <param name="value">The value to assign to the target object. If the value has
        /// a collection type compatible with the <paramref name="maybeCollectionTarget"/> target,
        /// the contents will be transferred to the target object, else this parameter value
        /// will be added to the target itself.</param>
        /// <returns><c>true</c>, if the method could handle the assignment, else <c>false</c>.</returns>
        public static bool CheckHandleCollectionAssignment(object maybeCollectionTarget, object value)
        {
            if (maybeCollectionTarget == null || value == null)
            {
                return(false);
            }
            Type targetType = maybeCollectionTarget.GetType();
            // Check for List
            Type       resultType;
            Type       entryType;
            MethodInfo method;

            FindImplementedListType(targetType, out resultType, out entryType);
            if (resultType != null)
            {
                method = entryType == null?targetType.GetMethod("Add") : targetType.GetMethod("Add", new Type[] { entryType });

                // Have to cast to ICollection, because the type converter cannot cope with the situation corretcly if we cast to IEnumerable
                ICollection col;
                object      converted;
                var         collectionTypeConverter = TypeConverter.CustomCollectionTypeConverter;
                if (collectionTypeConverter != null && collectionTypeConverter(value, targetType, out converted))
                {
                    col = (ICollection)converted;
                }
                else
                {
                    col = (ICollection)TypeConverter.Convert(value, typeof(ICollection));
                }

                if (col == null)
                {
                    // The type converter converts null to null rather than to an empty collection, so we have to handle this case explicitly
                    method.Invoke(maybeCollectionTarget, new object[] { null });
                }
                else
                {
                    foreach (object child in col)
                    {
                        method.Invoke(maybeCollectionTarget, new object[] { child });
                    }
                }
                return(true);
            }
            // Check for Dictionary
            Type keyType;
            Type valueType;

            FindImplementedDictionaryType(targetType, out resultType, out keyType, out valueType);
            Type sourceDictType;
            Type sourceKeyType;
            Type sourceValueType;

            FindImplementedDictionaryType(value.GetType(), out sourceDictType, out sourceKeyType, out sourceValueType);
            if (resultType != null && sourceDictType != null)
            {
                PropertyInfo targetItemProperty = keyType == null?targetType.GetProperty("Item") : targetType.GetProperty("Item", new Type[] { keyType });

                MethodInfo targetItemSetter = targetItemProperty.GetSetMethod();
                foreach (KeyValuePair <object, object> kvp in (IEnumerable)value)
                {
                    targetItemSetter.Invoke(maybeCollectionTarget, new object[] { kvp.Key, kvp.Value });
                }
                return(true);
            }
            // Check for IAddChild
            if (IsIAddChild(maybeCollectionTarget.GetType(), out method, out entryType))
            {
                foreach (object child in (ICollection)TypeConverter.Convert(value, typeof(ICollection)))
                {
                    method.Invoke(maybeCollectionTarget, new object[] { TypeConverter.Convert(child, entryType) });
                }
                return(true);
            }
            return(false);
        }