示例#1
0
        public static string ConvertFromInvariantString(string type, string source)
        {
            string value = source.Trim();

            if (IsNullableType(type, out string underlyingType))
            {
                if (value == "null")
                {
                    return("null");
                }
            }

            string result;

            switch (underlyingType)
            {
            case "global::System.SByte":
            case "global::System.UInt16":
            case "global::System.UInt32":
            case "global::System.UInt64":
                // Note: for numeric types, removing the quotation marks is sufficient
                // (+ potential additional letter to tell the actual type because casts
                // from int to double for example causes an exception).
                result = value;
                break;

            case "global::System.Decimal":
                result = PrepareStringForDecimal(value);
                break;

            case "global::System.Char":
                result = PrepareStringForChar(value);
                break;

            case "global::System.Object":
                result = PrepareStringForString(source);
                break;

            default:
                // return after escaping (note: we use value and not stringValue
                // because it can be a string that starts or ends with spaces)
                result = CoreTypesHelper.ConvertFromInvariantStringHelper(
                    source,
                    underlyingType
                    );
                break;
            }

            return(result);
        }
        private static void TraverseNextElement(
            XElement currentElement,
            int currentElementIndex,
            /*Stack<Dictionary<int, int>> indexesMapper*/ Stack <List <int> > indexesMapper,
            ReflectionOnSeparateAppDomainHandler reflectionOnSeparateAppDomain)
        {
            bool skipTraversalOfChildren = false;

            // Copy the children into a new array so that if we remove items from the collection,
            // it does not affect the traversal
            XElement[] children = currentElement.Elements().ToArray();

            // Check if the current element is an object (rather than a property)
            bool isElementAnObject = !currentElement.Name.LocalName.Contains(".");
            var  indexesMap        = new List <int>(children.Length);

            if (isElementAnObject)
            {
                //----------------------------------
                // CASE: OBJECT (e.g. <Button> or <TextBlock>)
                //----------------------------------

                // Make a list of all the child nodes that are not part of a property of the current
                // element (e.g. if the current element is a Border that contains a Button, we detect
                // "<Button>" but we ignore "<Border.Child>" and "<ToolTipService.ToolTip>" because
                // they are properties)
                List <XElement> nodesThatAreNotPropertiesOfTheObject = new List <XElement>();
                XElement        child;
                for (int i = 0; i < children.Length; i++)
                {
                    child = children[i];
                    if (!child.Name.LocalName.Contains("."))
                    {
                        nodesThatAreNotPropertiesOfTheObject.Add(child);
                        indexesMap.Add(i);
                    }
                }

                //-------------------------------------------------------------
                // Explicitly add the "ContentProperty" to the XAML. For example,
                //   <Border>
                //     <TextBlock/>
                //   </Border>
                // becomes
                //   <Border>
                //     <Border.Child>
                //       <TextBlock/>
                //     </Border.Child>
                //   </Border>
                //-------------------------------------------------------------
                // If that list is not empty, put those child elements into a group, which name is
                // the default children property (aka "ContentProperty") of the parent
                if (nodesThatAreNotPropertiesOfTheObject.Count > 0)
                {
                    // Find out the name of the default children property (aka "ContentProperty") of the current element:
                    string namespaceName, localName, assemblyNameIfAny;
                    GettingInformationAboutXamlTypes.GetClrNamespaceAndLocalName(currentElement.Name, out namespaceName, out localName, out assemblyNameIfAny);
                    var      contentPropertyName = reflectionOnSeparateAppDomain.GetContentPropertyName(namespaceName, localName, assemblyNameIfAny);
                    XElement contentWrapper      = currentElement;

                    if (contentPropertyName != null)
                    {
                        // Wrap the child elements
                        contentWrapper = new XElement(currentElement.Name + "." + contentPropertyName);
                    }

                    foreach (var childElement in nodesThatAreNotPropertiesOfTheObject)
                    {
                        childElement.Remove();
                    }

                    contentWrapper.Add(nodesThatAreNotPropertiesOfTheObject.ToArray <object>());

                    if (contentWrapper != currentElement)
                    {
                        currentElement.Add(contentWrapper);
                    }
                }

                //-------------------------------------------------------------
                // If there is some direct text content (such as <Button>content</Button), convert
                // the text into an attribute (such as <Button Content="content"></Button>) if the
                // element has the "[ContentProperty]" attribute.
                // Note: if the type is a system type (such as <sys:Double>50</sys:Double>), we
                // ignore it because later its value will be directly assigned.
                // Similarly, if the type is an Enum or a known type from the OpenSilver runtime
                // (for instance Thickness, Rect, Size...), we also ignore it because later it will
                // be transformed into a call to the "TypeFromStringConverters" class.
                //-------------------------------------------------------------
                XText directTextContent;
                if (ContainsTextNode(currentElement, out directTextContent))
                {
                    // Read the content
                    string contentValue = directTextContent.Value;

                    // Get information about the element namespace and assembly
                    string namespaceName, localName, assemblyNameIfAny;
                    GettingInformationAboutXamlTypes.GetClrNamespaceAndLocalName(
                        currentElement.Name, out namespaceName, out localName, out assemblyNameIfAny
                        );

                    string elementTypeInCSharp = reflectionOnSeparateAppDomain.GetCSharpEquivalentOfXamlTypeAsString(
                        namespaceName, localName, assemblyNameIfAny, false
                        );


                    // Distinguish system types (string, double, etc.) to other types
                    if (SystemTypesHelper.IsSupportedSystemType(elementTypeInCSharp.Substring("global::".Length), assemblyNameIfAny))
                    {
                        // In this case we do nothing because system types are handled
                        // later in the process. Example: "<sys:Double>50</sys:Double>"
                        // becomes "Double x = 50;"
                    }
                    else if (reflectionOnSeparateAppDomain.IsTypeAnEnum(namespaceName, localName, assemblyNameIfAny) ||
                             CoreTypesHelper.IsSupportedCoreType(elementTypeInCSharp.Substring("global::".Length), assemblyNameIfAny))
                    {
                        // Add the attribute that will tell the compiler to later
                        // intialize the type by converting from the string using the
                        // "TypeFromStringConverters" class
                        currentElement.SetAttributeValue(InitializedFromStringAttribute, contentValue);

                        // Remove the direct text content
                        directTextContent.Remove();
                    }
                    else
                    {
                        // Ensure the content is not empty
                        if (!string.IsNullOrWhiteSpace(contentValue)) //todo: do we really need this?
                        {
                            List <int> siblings = indexesMapper.Peek();

                            // If it is the first child, we want to trim the start of the string. (Silverlight behavior)
                            if (currentElementIndex == siblings[0]) //at least of size 1 (it contains currentElement)
                            {
                                contentValue = contentValue.TrimStart();
                            }

                            // If it is the last child, we want to trim the end of the string. (Silverlight behavior)
                            if (currentElementIndex == siblings[siblings.Count - 1])
                            {
                                contentValue = contentValue.TrimEnd();
                            }

                            // Replace multiple spaces (and line returns) with just one space (same behavior as in WPF)
                            // cf. http://stackoverflow.com/questions/1279859/how-to-replace-multiple-white-spaces-with-one-white-space
                            contentValue = Regex.Replace(contentValue, @"\s{2,}", " ");

                            string contentPropertyName =
                                reflectionOnSeparateAppDomain.GetContentPropertyName(
                                    namespaceName, localName, assemblyNameIfAny
                                    );

                            if (!string.IsNullOrEmpty(contentPropertyName))
                            {
                                // Verify that the attribute is not already set
                                if (currentElement.Attribute(contentPropertyName) != null)
                                {
                                    throw new wpf::System.Windows.Markup.XamlParseException(
                                              string.Format("The property '{0}' is set more than once.", contentPropertyName)
                                              );
                                }

                                // SPECIAL CASE: If we are in a TextBlock, we want to set the
                                // property "TextBlock.Text" instead of "TextBlock.Inlines"
                                if ((currentElement.Name == GeneratingCSharpCode.DefaultXamlNamespace + "TextBlock") ||
                                    (currentElement.Name == GeneratingCSharpCode.DefaultXamlNamespace + "Run"))
                                {
                                    contentPropertyName = "Text";
                                }

                                // Add the Content attribute
                                XAttribute attribute = new XAttribute(contentPropertyName, contentValue);
                                currentElement.Add(attribute);

                                // Remove the direct text content
                                directTextContent.Remove();
                            }
                            else
                            {
                                throw new wpf::System.Windows.Markup.XamlParseException(
                                          string.Format("The element '{0}' does not support direct content.", currentElement.Name)
                                          );
                            }
                        }
                    }
                }
            }
            else
            {
                //----------------------------------
                // CASE: PROPERTY (e.g. <Button.Visibility> or <TextBlock.Text> or <ToolTipService.ToolTip>)
                //----------------------------------

                // If there is some direct text content (such as <Button.Visibility>Collapsed</Button.Visibility>
                // or <ToolTipService.ToolTip>Test</ToolTipService.ToolTip>), we convert the text into an attribute
                // (such as <Button Visibility="Collapsed"></Button> or <Button ToolTipService.ToolTip="Test></Button>)
                XText directTextContent;
                if (ContainsTextNode(currentElement, out directTextContent))
                {
                    // Check if we are on a direct object property (such as <Button.Visibility>) or an attached property
                    // (such as <ToolTipService.ToolTip>). For example, if the current element is <TextBlock.Text> and
                    // the parent is <TextBlock>, the result is true. Conversely, if the current element is
                    // <ToolTipService.ToolTip> and the parent is <Border>, the result is false.
                    bool isAttachedProperty =
                        currentElement.Parent.Name != (currentElement.Name.Namespace + currentElement.Name.LocalName.Substring(0, currentElement.Name.LocalName.IndexOf(".")));

                    // Read the content
                    string contentValue = directTextContent.Value;

                    // Get the property name
                    string contentPropertyName = isAttachedProperty ?
                                                 currentElement.Name.LocalName :
                                                 currentElement.Name.LocalName.Substring(currentElement.Name.LocalName.IndexOf(".") + 1);

                    // Replace multiple spaces (and line returns) with just one space (same behavior as in WPF):
                    //cf. http://stackoverflow.com/questions/1279859/how-to-replace-multiple-white-spaces-with-one-white-space
                    contentValue = Regex.Replace(contentValue, @"\s{2,}", " ").Trim();
                    if (!string.IsNullOrEmpty(contentValue))
                    {
                        contentValue = contentValue[0] == '{' ? "{}" + contentValue : contentValue;
                    }

                    // Verify that the attribute is not already set:
                    if (currentElement.Attribute(contentPropertyName) != null)
                    {
                        throw new wpf::System.Windows.Markup.XamlParseException(
                                  string.Format("The property '{0}' is set more than once.", contentPropertyName)
                                  );
                    }

                    // Add the attribute
                    currentElement.Parent.Add(
                        new XAttribute(contentPropertyName, contentValue)
                        );

                    // Remove the element
                    currentElement.Remove();

                    // It's useless to traverse the children because we have removed the element
                    skipTraversalOfChildren = true;
                }
                else
                {
                    XElement child;
                    for (int i = 0; i < children.Length; i++)
                    {
                        child = children[i];
                        if (!child.Name.LocalName.Contains("."))
                        {
                            indexesMap.Add(i);
                        }
                    }
                }
            }

            // Recursion
            if (!skipTraversalOfChildren)
            {
                indexesMapper.Push(indexesMap);
                int i = 0;
                foreach (var childElements in children)
                {
                    TraverseNextElement(childElements, i, indexesMapper, reflectionOnSeparateAppDomain);
                    ++i;
                }
                indexesMapper.Pop();
            }
        }