/// <summary> /// Finds the specified property, or creates it if it doesn't exist. /// </summary> public XamlProperty FindOrCreateAttachedProperty(Type ownerType, string propertyName) { if (ownerType == null) { throw new ArgumentNullException("ownerType"); } if (propertyName == null) { throw new ArgumentNullException("propertyName"); } foreach (XamlProperty p in properties) { if (p.IsAttached && p.PropertyTargetType == ownerType && p.PropertyName == propertyName) { return(p); } } XamlPropertyInfo info = XamlParser.TryFindAttachedProperty(ownerType, propertyName); if (info == null) { throw new ArgumentException( "The attached property '" + propertyName + "' doesn't exist on " + ownerType.FullName, "propertyName"); } XamlProperty newProperty = new XamlProperty(this, info); properties.Add(newProperty); return(newProperty); }
internal static void ParseObjectAttribute(XamlObject obj, XmlAttribute attribute, bool real) { XamlPropertyInfo propertyInfo = GetPropertyInfo(obj.Instance, obj.ElementType, attribute, obj.OwnerDocument.TypeFinder); XamlPropertyValue value = null; var valueText = attribute.Value; if (valueText.StartsWith("{", StringComparison.Ordinal) && !valueText.StartsWith("{}", StringComparison.Ordinal)) { var xamlObject = MarkupExtensionParser.Parse(valueText, obj, real ? attribute : null); value = xamlObject; } else { if (real) { value = new XamlTextValue(obj.OwnerDocument, attribute); } else { value = new XamlTextValue(obj.OwnerDocument, valueText); } } var property = new XamlProperty(obj, propertyInfo, value); obj.AddProperty(property); }
internal override void AddNodeTo(XamlProperty property) { XamlObject holder; if (!UpdateXmlAttribute(true, out holder)) { property.AddChildNodeToProperty(element); } UpdateMarkupExtensionChain(); }
/// <summary> /// Finds the specified property, or creates it if it doesn't exist. /// </summary> public XamlProperty FindOrCreateProperty(string propertyName) { if (propertyName == null) { throw new ArgumentNullException("propertyName"); } // if (propertyName == ContentPropertyName) // return foreach (XamlProperty p in properties) { if (!p.IsAttached && p.PropertyName == propertyName) { return(p); } } PropertyDescriptorCollection propertyDescriptors = TypeDescriptor.GetProperties(instance); PropertyDescriptor propertyInfo = propertyDescriptors[propertyName]; XamlProperty newProperty; if (propertyInfo == null) { propertyDescriptors = TypeDescriptor.GetProperties(this.elementType); propertyInfo = propertyDescriptors[propertyName]; } if (propertyInfo != null) { newProperty = new XamlProperty(this, new XamlNormalPropertyInfo(propertyInfo)); } else { EventDescriptorCollection events = TypeDescriptor.GetEvents(instance); EventDescriptor eventInfo = events[propertyName]; if (eventInfo == null) { events = TypeDescriptor.GetEvents(this.elementType); eventInfo = events[propertyName]; } if (eventInfo != null) { newProperty = new XamlProperty(this, new XamlEventPropertyInfo(eventInfo)); } else { throw new ArgumentException( "The property '" + propertyName + "' doesn't exist on " + elementType.FullName, "propertyName"); } } properties.Add(newProperty); return(newProperty); }
internal string GetPrefixForNamespace(string @namespace) { if (@namespace == XamlConstants.PresentationNamespace) { return(null); } string prefix = _xmlDoc.DocumentElement.GetPrefixOfNamespace(@namespace); if (_xmlDoc.DocumentElement.NamespaceURI == @namespace && _xmlDoc.Prefix == String.Empty) { return(string.Empty); } if (String.IsNullOrEmpty(prefix)) { prefix = _typeFinder.GetPrefixForXmlNamespace(@namespace); string existingNamespaceForPrefix = null; if (!String.IsNullOrEmpty(prefix)) { existingNamespaceForPrefix = _xmlDoc.DocumentElement.GetNamespaceOfPrefix(prefix); } if (String.IsNullOrEmpty(prefix) || !String.IsNullOrEmpty(existingNamespaceForPrefix) && existingNamespaceForPrefix != @namespace) { do { prefix = "Controls" + namespacePrefixCounter++; } while (!String.IsNullOrEmpty(_xmlDoc.DocumentElement.GetNamespaceOfPrefix(prefix))); } string xmlnsPrefix = _xmlDoc.DocumentElement.GetPrefixOfNamespace(XamlConstants.XmlnsNamespace); System.Diagnostics.Debug.Assert(!String.IsNullOrEmpty(xmlnsPrefix)); _xmlDoc.DocumentElement.SetAttribute(xmlnsPrefix + ":" + prefix, @namespace); if (@namespace == XamlConstants.DesignTimeNamespace) { var ignorableProp = new XamlProperty(this._rootElement, new XamlDependencyPropertyInfo(MarkupCompatibilityProperties.IgnorableProperty, true)); ignorableProp.SetAttribute(prefix); } } return(prefix); }
//TODO: reseting path property for binding doesn't work in XamlProperty //use CanResetValue() internal void OnPropertyChanged(XamlProperty property) { XamlObject holder; if (!UpdateXmlAttribute(false, out holder)) { if (holder != null && holder.XmlAttribute != null) { holder.XmlAttribute.OwnerElement.RemoveAttributeNode(holder.XmlAttribute); holder.xmlAttribute = null; holder.ParentProperty.AddChildNodeToProperty(holder.element); bool isThisUpdated = false; foreach (XamlObject propXamlObject in holder.Properties.Where((prop) => prop.IsSet) .Select((prop) => prop.PropertyValue) .OfType <XamlObject>()) { XamlObject innerHolder; bool updateResult = propXamlObject.UpdateXmlAttribute(true, out innerHolder); Debug.Assert(updateResult || innerHolder == null); if (propXamlObject == this) { isThisUpdated = true; } } if (!isThisUpdated) { this.UpdateXmlAttribute(true, out holder); } } } UpdateMarkupExtensionChain(); if (!element.HasChildNodes && !element.IsEmpty) { element.IsEmpty = true; } if (property == NameProperty) { if (NameChanged != null) { NameChanged(this, EventArgs.Empty); } } }
/// <summary>For use by XamlParser only.</summary> internal void AddProperty(XamlProperty property) { #if DEBUG if (property.IsAttached == false) { foreach (XamlProperty p in properties) { if (p.IsAttached == false && p.PropertyName == property.PropertyName) { throw new XamlLoadException("duplicate property:" + property.PropertyName); } } } #endif properties.Add(property); }
internal override void AddNodeTo(XamlProperty property) { if (attribute != null) { property.ParentObject.XmlElement.Attributes.Append(attribute); } else if (textValue != null) { attribute = property.SetAttribute(textValue); textValue = null; } else if (cDataSection != null) { property.AddChildNodeToProperty(cDataSection); } else { property.AddChildNodeToProperty(textNode); } }
/// <summary> /// Sets an attribute in the x:-namespace. /// </summary> public void SetXamlAttribute(string name, string value) { XamlProperty runtimeNameProperty = null; bool isNameChange = false; if (name == "Name") { isNameChange = true; string oldName = GetXamlAttribute("Name"); if (String.IsNullOrEmpty(oldName)) { runtimeNameProperty = this.NameProperty; if (runtimeNameProperty != null) { if (runtimeNameProperty.IsSet) { oldName = (string)runtimeNameProperty.ValueOnInstance; } else { runtimeNameProperty = null; } } } if (String.IsNullOrEmpty(oldName)) { oldName = null; } NameScopeHelper.NameChanged(this, oldName, value); } if (value == null) { element.RemoveAttribute(name, XamlConstants.XamlNamespace); } else { var prefix = element.GetPrefixOfNamespace(XamlConstants.XamlNamespace); var prefix2009 = element.GetPrefixOfNamespace(XamlConstants.Xaml2009Namespace); if (!string.IsNullOrEmpty(prefix)) { var attribute = element.OwnerDocument.CreateAttribute(prefix, name, XamlConstants.XamlNamespace); attribute.InnerText = value; element.SetAttributeNode(attribute); } else if (!string.IsNullOrEmpty(prefix2009)) { var attribute = element.OwnerDocument.CreateAttribute(prefix, name, XamlConstants.Xaml2009Namespace); attribute.InnerText = value; element.SetAttributeNode(attribute); } else { element.SetAttribute(name, XamlConstants.XamlNamespace, value); } } if (isNameChange) { bool nameChangedAlreadyRaised = false; if (runtimeNameProperty != null) { var handler = new EventHandler((sender, e) => nameChangedAlreadyRaised = true); this.NameChanged += handler; try { runtimeNameProperty.Reset(); } finally { this.NameChanged -= handler; } } if (NameChanged != null && !nameChangedAlreadyRaised) { NameChanged(this, EventArgs.Empty); } } }
internal abstract void AddNodeTo(XamlProperty property);
/// <summary> /// Create a XamlPropertyValue for the specified value instance. /// </summary> public XamlPropertyValue CreatePropertyValue(object instance, XamlProperty forProperty) { if (instance == null) { throw new ArgumentNullException("instance"); } Type elementType = instance.GetType(); TypeConverter c = TypeDescriptor.GetConverter(instance); var ctx = new DummyTypeDescriptorContext(this.ServiceProvider); ctx.Instance = instance; bool hasStringConverter = c.CanConvertTo(ctx, typeof(string)) && c.CanConvertFrom(typeof(string)); if (forProperty != null && hasStringConverter) { if (instance is SolidColorBrush && _colorBrushDictionary.ContainsKey(((SolidColorBrush)instance).Color)) { var name = _colorBrushDictionary[((SolidColorBrush)instance).Color]; return(new XamlTextValue(this, name)); } return(new XamlTextValue(this, c.ConvertToInvariantString(ctx, instance))); } string ns = GetNamespaceFor(elementType); string prefix = GetPrefixForNamespace(ns); XmlElement xml = _xmlDoc.CreateElement(prefix, elementType.Name, ns); if (hasStringConverter && (XamlObject.GetContentPropertyName(elementType) != null || IsNativeType(instance))) { xml.InnerText = c.ConvertToInvariantString(instance); } else if (instance is Brush && forProperty != null) { // TODO: this is a hacky fix, because Brush Editor doesn't // edit Design Items and so we have no XML, only the Brush // object and we need to parse the Brush to XAML! var s = new MemoryStream(); XamlWriter.Save(instance, s); s.Seek(0, SeekOrigin.Begin); XmlDocument doc = new XmlDocument(); doc.Load(s); xml = (XmlElement)_xmlDoc.ImportNode(doc.DocumentElement, true); var attLst = xml.Attributes.Cast <XmlAttribute>().ToList(); foreach (XmlAttribute att in attLst) { if (att.Name.StartsWith(XamlConstants.Xmlns)) { var rootAtt = doc.DocumentElement.GetAttributeNode(att.Name); if (rootAtt != null && rootAtt.Value == att.Value) { xml.Attributes.Remove(att); } } } } return(new XamlObject(this, xml, elementType, instance)); }
void ParseObjectChildElementAsPropertyElement(XamlObject obj, XmlElement element, XamlPropertyInfo defaultProperty) { Debug.Assert(element.LocalName.Contains(".")); // this is a element property syntax XamlPropertyInfo propertyInfo = GetPropertyInfo(settings.TypeFinder, obj.Instance, obj.ElementType, element.NamespaceURI, element.LocalName); bool valueWasSet = false; object collectionInstance = null; bool isElementChildACollectionForProperty = false; XamlProperty collectionProperty = null; if (propertyInfo.IsCollection) { if (defaultProperty != null && defaultProperty.FullyQualifiedName == propertyInfo.FullyQualifiedName) { foreach (XamlProperty existing in obj.Properties) { if (existing.propertyInfo == defaultProperty) { collectionProperty = existing; break; } } } if (collectionProperty == null) { obj.AddProperty(collectionProperty = new XamlProperty(obj, propertyInfo)); } isElementChildACollectionForProperty = IsElementChildACollectionForProperty(settings.TypeFinder, element, propertyInfo); if (isElementChildACollectionForProperty) { collectionProperty.ParserSetPropertyElement((XmlElement)element.ChildNodes.Cast <XmlNode>() .Where(x => !(x is XmlWhitespace)) .First()); } else { collectionInstance = collectionProperty.propertyInfo.GetValue(obj.Instance); collectionProperty.ParserSetPropertyElement(element); collectionInstance = collectionInstance ?? Activator.CreateInstance(collectionProperty.propertyInfo.ReturnType); } } XmlSpace oldXmlSpace = currentXmlSpace; if (element.HasAttribute("xml:space")) { currentXmlSpace = (XmlSpace)Enum.Parse(typeof(XmlSpace), element.GetAttribute("xml:space"), true); } foreach (XmlNode childNode in element.ChildNodes) { currentParsedNode = childNode; XamlPropertyValue childValue = ParseValue(childNode); if (childValue != null) { if (propertyInfo.IsCollection) { if (isElementChildACollectionForProperty) { collectionProperty.PropertyValue = childValue; } else { CollectionSupport.AddToCollection(propertyInfo.ReturnType, collectionInstance, childValue); collectionProperty.ParserAddCollectionElement(element, childValue); } } else { if (valueWasSet) { throw new XamlLoadException("non-collection property may have only one child element"); } valueWasSet = true; XamlProperty xp = new XamlProperty(obj, propertyInfo, childValue); xp.ParserSetPropertyElement(element); obj.AddProperty(xp); } } } currentParsedNode = element; currentXmlSpace = oldXmlSpace; }
void ParseObjectContent(XamlObject obj, XmlElement element, XamlPropertyInfo defaultProperty, XamlTextValue initializeFromTextValueInsteadOfConstructor) { bool isDefaultValueSet = false; XamlProperty collectionProperty = null; object collectionInstance = null; Type collectionType = null; XmlElement collectionPropertyElement = null; var elementChildNodes = GetNormalizedChildNodes(element); if (defaultProperty == null && obj.Instance != null && CollectionSupport.IsCollectionType(obj.Instance.GetType())) { XamlObject parentObj = obj.ParentObject; var parentElement = element.ParentNode; XamlPropertyInfo propertyInfo; if (parentObj != null) { propertyInfo = GetPropertyInfo(settings.TypeFinder, parentObj.Instance, parentObj.ElementType, parentElement.NamespaceURI, parentElement.LocalName); collectionProperty = FindExistingXamlProperty(parentObj, propertyInfo); } collectionInstance = obj.Instance; collectionType = obj.ElementType; collectionPropertyElement = element; } else if (defaultProperty != null && defaultProperty.IsCollection && !element.IsEmpty) { foreach (XmlNode childNode in elementChildNodes) { currentParsedNode = childNode; XmlElement childElement = childNode as XmlElement; if (childElement == null || !ObjectChildElementIsPropertyElement(childElement)) { obj.AddProperty(collectionProperty = new XamlProperty(obj, defaultProperty)); collectionType = defaultProperty.ReturnType; collectionInstance = defaultProperty.GetValue(obj.Instance); break; } } } currentParsedNode = element; if (collectionType != null && collectionInstance == null && elementChildNodes.Count() == 1) { var firstChild = elementChildNodes.First() as XmlElement; if (ObjectChildElementIsCollectionInstance(firstChild, collectionType)) { collectionInstance = ParseObject(firstChild); collectionProperty.PropertyValue = (XamlPropertyValue)collectionInstance; } else { throw new XamlLoadException("Collection Instance is null"); } } else { foreach (XmlNode childNode in elementChildNodes) { currentParsedNode = childNode; XmlElement childElement = childNode as XmlElement; if (childElement != null) { if (childElement.NamespaceURI == XamlConstants.XamlNamespace) { continue; } if (ObjectChildElementIsPropertyElement(childElement)) { ParseObjectChildElementAsPropertyElement(obj, childElement, defaultProperty); continue; } } if (initializeFromTextValueInsteadOfConstructor != null) { continue; } XamlPropertyValue childValue = ParseValue(childNode); if (childValue != null) { if (collectionProperty != null) { collectionProperty.ParserAddCollectionElement(collectionPropertyElement, childValue); CollectionSupport.AddToCollection(collectionType, collectionInstance, childValue); } else if (collectionProperty == null && collectionInstance is ResourceDictionary) { CollectionSupport.AddToCollection(collectionType, collectionInstance, childValue); } else { if (defaultProperty == null) { throw new XamlLoadException( "This element does not have a default value, cannot assign to it"); } if (isDefaultValueSet) { throw new XamlLoadException("default property may have only one value assigned"); } obj.AddProperty(new XamlProperty(obj, defaultProperty, childValue)); isDefaultValueSet = true; } } } } currentParsedNode = element; }
internal CollectionElementsCollection(XamlProperty property) { this.property = property; }