/// <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 static XamlPropertyInfo GetPropertyInfo(XamlTypeFinder typeFinder, object elementInstance, Type elementType, string xmlNamespace, string localName, bool tryFindAllProperties = false) { string typeName, propertyName; SplitQualifiedIdentifier(localName, out typeName, out propertyName); Type propertyType = FindType(typeFinder, xmlNamespace, typeName); //Tries to Find All properties, even if they are not attached (For Setters, Bindings, ...) if (tryFindAllProperties) { XamlPropertyInfo propertyInfo = null; try { propertyInfo = FindProperty(elementInstance, propertyType, propertyName); } catch (Exception) { } if (propertyInfo != null) { return(propertyInfo); } } if (elementType.IsAssignableFrom(propertyType) || propertyType.IsAssignableFrom(elementType)) { return(FindProperty(elementInstance, propertyType, propertyName)); } else { // This is an attached property return(FindAttachedProperty(propertyType, propertyName)); } }
static bool IsElementChildACollectionForProperty(XamlTypeFinder typeFinder, XmlElement element, XamlPropertyInfo propertyInfo) { var nodes = element.ChildNodes.Cast <XmlNode>().Where(x => !(x is XmlWhitespace)).ToList(); return(nodes.Count == 1 && propertyInfo.ReturnType.IsAssignableFrom( FindType(typeFinder, nodes[0].NamespaceURI, nodes[0].LocalName))); }
static XamlProperty FindExistingXamlProperty(XamlObject obj, XamlPropertyInfo propertyInfo) { foreach (XamlProperty existing in obj.Properties) { if (existing.propertyInfo.FullyQualifiedName == propertyInfo.FullyQualifiedName) { return(existing); } } throw new XamlLoadException("Existing XamlProperty " + propertyInfo.FullyQualifiedName + " not found."); }
// for use by parser only internal XamlProperty(XamlObject parentObject, XamlPropertyInfo propertyInfo, XamlPropertyValue propertyValue) : this(parentObject, propertyInfo) { PossiblyNameChanged(null, propertyValue); this.propertyValue = propertyValue; if (propertyValue != null) { propertyValue.ParentProperty = this; } UpdateValueOnInstance(); }
internal override object GetValueFor(XamlPropertyInfo targetProperty) { if (ParentProperty == null) { throw new InvalidOperationException("Cannot call GetValueFor while ParentProperty is null"); } if (targetProperty == null) { return(this.Text); } return(XamlParser.CreateObjectFromAttributeText(Text, targetProperty, ParentProperty.ParentObject)); }
internal override object GetValueFor(XamlPropertyInfo targetProperty) { if (IsMarkupExtension) { var value = ProvideValue(); if (value is string && targetProperty != null && targetProperty.ReturnType != typeof(string)) { return(XamlParser.CreateObjectFromAttributeText((string)value, targetProperty, this)); } return(value); } else { return(instance); } }
static XamlPropertyInfo FindAttachedProperty(Type elementType, string propertyName) { XamlPropertyInfo pi = TryFindAttachedProperty(elementType, propertyName); if (pi == null) { pi = TryFindAttachedEvent(elementType, propertyName); } if (pi != null) { return(pi); } else { throw new XamlLoadException("attached property " + elementType.Name + "." + propertyName + " not found"); } }
internal XamlProperty(XamlObject parentObject, XamlPropertyInfo propertyInfo) { this.parentObject = parentObject; this.propertyInfo = propertyInfo; if (propertyInfo.IsCollection) { isCollection = true; collectionElements = new CollectionElementsCollection(this); collectionElements.CollectionChanged += OnCollectionChanged; if (propertyInfo.Name.Equals(XamlConstants.ResourcesPropertyName, StringComparison.Ordinal) && propertyInfo.ReturnType == typeof(ResourceDictionary)) { isResources = true; } } }
internal static XamlPropertyInfo FindProperty(object elementInstance, Type propertyType, string propertyName) { PropertyDescriptor propertyInfo = TypeDescriptor.GetProperties(propertyType)[propertyName]; if (propertyInfo == null && elementInstance != null) { propertyInfo = TypeDescriptor.GetProperties(elementInstance) .OfType <DependencyPropertyDescriptor>() .FirstOrDefault(x => x.IsAttached && x.Name == propertyName); } if (propertyInfo != null) { return(new XamlNormalPropertyInfo(propertyInfo)); } else { XamlPropertyInfo pi = TryFindAttachedProperty(propertyType, propertyName); if (pi != null) { return(pi); } } EventDescriptorCollection events; if (elementInstance != null) { events = TypeDescriptor.GetEvents(elementInstance); } else { events = TypeDescriptor.GetEvents(propertyType); } EventDescriptor eventInfo = events[propertyName]; if (eventInfo != null) { return(new XamlEventPropertyInfo(eventInfo)); } throw new XamlLoadException("property " + propertyName + " not found"); }
internal static object CreateObjectFromAttributeText(string valueText, XamlPropertyInfo targetProperty, XamlObject scope) { if (targetProperty.ReturnType == typeof(Uri)) { return(scope.OwnerDocument.TypeFinder.ConvertUriToLocalUri(new Uri(valueText, UriKind.RelativeOrAbsolute))); } else if (targetProperty.ReturnType == typeof(ImageSource)) { var uri = scope.OwnerDocument.TypeFinder.ConvertUriToLocalUri(new Uri(valueText, UriKind.RelativeOrAbsolute)); return(targetProperty.TypeConverter.ConvertFromString( scope.OwnerDocument.GetTypeDescriptorContext(scope), CultureInfo.InvariantCulture, uri.ToString())); } return(targetProperty.TypeConverter.ConvertFromString( scope.OwnerDocument.GetTypeDescriptorContext(scope), CultureInfo.InvariantCulture, valueText)); }
protected override void InsertItem(int index, XamlPropertyValue item) { XamlPropertyInfo info = property.propertyInfo; object collection = info.GetValue(property.ParentObject.Instance); if (!CollectionSupport.TryInsert(info.ReturnType, collection, item, index)) { CollectionSupport.AddToCollection(info.ReturnType, collection, item); } item.ParentProperty = property; property.InsertNodeInCollection(item.GetNodeForCollection(), index); base.InsertItem(index, item); if (CollectionChanged != null) { CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index)); } }
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value == null) { return(null); } if (value is string) { XamlTypeResolverProvider xamlTypeResolver = (XamlTypeResolverProvider)context.GetService(typeof(XamlTypeResolverProvider)); if (xamlTypeResolver == null) { throw new XamlLoadException("XamlTypeResolverProvider not found in type descriptor context."); } XamlPropertyInfo prop = xamlTypeResolver.ResolveProperty((string)value); if (prop == null) { throw new XamlLoadException("Could not find property " + value + "."); } XamlDependencyPropertyInfo depProp = prop as XamlDependencyPropertyInfo; if (depProp != null) { return(depProp.DependencyProperty); } FieldInfo field = prop.TargetType.GetField(prop.Name + "Property", BindingFlags.Public | BindingFlags.Static); if (field != null && field.FieldType == typeof(DependencyProperty)) { return((DependencyProperty)field.GetValue(null)); } throw new XamlLoadException("Property " + value + " is not a dependency property."); } else { return(base.ConvertFrom(context, culture, value)); } }
protected override void RemoveItem(int index) { XamlPropertyInfo info = property.propertyInfo; object collection = info.GetValue(property.ParentObject.Instance); if (!CollectionSupport.RemoveItemAt(info.ReturnType, collection, index)) { var propertyValue = this[index]; CollectionSupport.RemoveItem(info.ReturnType, collection, propertyValue.GetValueFor(info), propertyValue); } var item = this[index]; item.RemoveNodeFromParent(); item.ParentProperty = null; base.RemoveItem(index); if (CollectionChanged != null && !isClearing) { CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); } }
/// <summary> /// used internally by the XamlParser. /// </summary> internal abstract object GetValueFor(XamlPropertyInfo targetProperty);
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; }
XamlObject ParseObject(XmlElement element) { Type elementType = settings.TypeFinder.GetType(element.NamespaceURI, element.LocalName); if (typeof(FrameworkTemplate).IsAssignableFrom(elementType)) { var xamlObj = new XamlObject(document, element, elementType, TemplateHelper.GetFrameworkTemplate(element, currentXamlObject)); xamlObj.ParentObject = currentXamlObject; return(xamlObj); } if (elementType == null) { elementType = settings.TypeFinder.GetType(element.NamespaceURI, element.LocalName + "Extension"); if (elementType == null) { throw new XamlLoadException("Cannot find type " + element.Name); } } XmlSpace oldXmlSpace = currentXmlSpace; XamlObject parentXamlObject = currentXamlObject; if (element.HasAttribute("xml:space")) { currentXmlSpace = (XmlSpace)Enum.Parse(typeof(XmlSpace), element.GetAttribute("xml:space"), true); } XamlPropertyInfo defaultProperty = GetDefaultProperty(elementType); XamlTextValue initializeFromTextValueInsteadOfConstructor = null; if (defaultProperty == null) { int numberOfTextNodes = 0; bool onlyTextNodes = true; foreach (XmlNode childNode in element.ChildNodes) { if (childNode.NodeType == XmlNodeType.Text) { numberOfTextNodes++; } else if (childNode.NodeType == XmlNodeType.Element) { onlyTextNodes = false; } } if (elementType == typeof(string) && numberOfTextNodes == 0) { initializeFromTextValueInsteadOfConstructor = new XamlTextValue(document, string.Empty); } else if (onlyTextNodes && numberOfTextNodes == 1) { foreach (XmlNode childNode in element.ChildNodes) { if (childNode.NodeType == XmlNodeType.Text) { currentParsedNode = childNode; initializeFromTextValueInsteadOfConstructor = (XamlTextValue)ParseValue(childNode); } } } } currentParsedNode = element; object instance; if (initializeFromTextValueInsteadOfConstructor != null) { instance = TypeDescriptor.GetConverter(elementType) .ConvertFromString( document.GetTypeDescriptorContext(null), CultureInfo.InvariantCulture, initializeFromTextValueInsteadOfConstructor.Text); } else { instance = settings.CreateInstanceCallback(elementType, emptyObjectArray); } XamlObject obj = new XamlObject(document, element, elementType, instance); currentXamlObject = obj; obj.ParentObject = parentXamlObject; if (parentXamlObject == null && obj.Instance is DependencyObject) { NameScope.SetNameScope((DependencyObject)obj.Instance, new NameScope()); } ISupportInitialize iSupportInitializeInstance = instance as ISupportInitialize; if (iSupportInitializeInstance != null) { iSupportInitializeInstance.BeginInit(); } foreach (XmlAttribute attribute in element.Attributes) { if (attribute.Value.StartsWith("clr-namespace", StringComparison.OrdinalIgnoreCase)) { // the format is "clr-namespace:<Namespace here>;assembly=<Assembly name here>" var clrNamespace = attribute.Value.Split(new[] { ':', ';', '=' }); if (clrNamespace.Length == 4) { // get the assembly name var assembly = settings.TypeFinder.LoadAssembly(clrNamespace[3]); if (assembly != null) { settings.TypeFinder.RegisterAssembly(assembly); } } else { // if no assembly name is there, then load the assembly of the opened file. var assembly = settings.TypeFinder.LoadAssembly(null); if (assembly != null) { settings.TypeFinder.RegisterAssembly(assembly); } } } if (attribute.NamespaceURI == XamlConstants.XmlnsNamespace) { continue; } if (attribute.Name == "xml:space") { continue; } if (GetAttributeNamespace(attribute) == XamlConstants.XamlNamespace || GetAttributeNamespace(attribute) == XamlConstants.Xaml2009Namespace) { if (attribute.LocalName == "Name") { try { NameScopeHelper.NameChanged(obj, null, attribute.Value); } catch (Exception x) { ReportException(x, attribute); } } continue; } ParseObjectAttribute(obj, attribute); } ParseObjectContent(obj, element, defaultProperty, initializeFromTextValueInsteadOfConstructor); if (iSupportInitializeInstance != null) { iSupportInitializeInstance.EndInit(); } currentXmlSpace = oldXmlSpace; currentXamlObject = parentXamlObject; return(obj); }
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; }