diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Tests/XamlDom/SamplesTests.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Tests/XamlDom/SamplesTests.cs index eac9571842..6983391839 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Tests/XamlDom/SamplesTests.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Tests/XamlDom/SamplesTests.cs @@ -112,6 +112,21 @@ namespace ICSharpCode.WpfDesign.Tests.XamlDom Go To Page 2 +"); + } + + [Test] + public void Resources() + { + TestLoading(@" + + + + + "); } } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/CollectionSupport.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/CollectionSupport.cs index e4730774ea..2194cf2613 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/CollectionSupport.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/CollectionSupport.cs @@ -21,9 +21,9 @@ namespace ICSharpCode.WpfDesign.XamlDom public static bool IsCollectionType(Type type) { return typeof(IList).IsAssignableFrom(type) - || typeof(IDictionary).IsAssignableFrom(type) || type.IsArray - || typeof(IAddChild).IsAssignableFrom(type); + || typeof(IAddChild).IsAssignableFrom(type) + || typeof(ResourceDictionary).IsAssignableFrom(type); } public static void AddToCollection(Type collectionType, object collectionInstance, XamlPropertyValue newElement) @@ -35,6 +35,14 @@ namespace ICSharpCode.WpfDesign.XamlDom } else { addChild.AddChild(newElement.GetValueFor(null)); } + } else if (collectionInstance is ResourceDictionary) { + object val = newElement.GetValueFor(null); + object key = newElement is XamlObject ? ((XamlObject)newElement).GetXamlAttribute("Key") : null; + if (key == null) { + if (val is Style) + key = ((Style)val).TargetType; + } + ((ResourceDictionary)collectionInstance).Add(key, val); } else { collectionType.InvokeMember( "Add", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance, diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/MarkupExtensionParser.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/MarkupExtensionParser.cs index 58d93af3c2..4c70c356af 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/MarkupExtensionParser.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/MarkupExtensionParser.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.Globalization; using System.Linq; using System.Runtime.Serialization; @@ -218,10 +219,12 @@ namespace ICSharpCode.WpfDesign.XamlDom static class MarkupExtensionParser { - public static MarkupExtension ConstructMarkupExtension(string attributeText, XmlElement containingElement, XamlDocument document) + public static MarkupExtension ConstructMarkupExtension(string attributeText, XamlObject containingObject, XamlTypeResolverProvider typeResolver) { - if (containingElement == null) - throw new ArgumentNullException("containingElement"); + if (containingObject == null) + throw new ArgumentNullException("containingObject"); + + Debug.WriteLine("ConstructMarkupExtension " + attributeText); List markupExtensionTokens = MarkupExtensionTokenizer.Tokenize(attributeText); if (markupExtensionTokens.Count < 3 @@ -233,26 +236,14 @@ namespace ICSharpCode.WpfDesign.XamlDom } string typeName = markupExtensionTokens[1].Value; - string typeNamespaceUri; - string typeLocalName; - if (typeName.Contains(":")) { - typeNamespaceUri = containingElement.GetNamespaceOfPrefix(typeName.Substring(0, typeName.IndexOf(':'))); - typeLocalName = typeName.Substring(typeName.IndexOf(':') + 1); - } else { - typeNamespaceUri = containingElement.NamespaceURI; - typeLocalName = typeName; - } - if (string.IsNullOrEmpty(typeNamespaceUri)) - throw new XamlMarkupExtensionParseException("Unrecognized namespace prefix in type " + typeName); - Type extensionType = null; - if (typeNamespaceUri == "http://schemas.microsoft.com/winfx/2006/xaml" && typeLocalName == "Type") { - extensionType = typeof(TypeExtension); - } else { - extensionType = document.TypeFinder.GetType(typeNamespaceUri, typeLocalName + "Extension"); - } + Type extensionType = typeResolver.Resolve(typeName + "Extension"); if (extensionType == null || !typeof(MarkupExtension).IsAssignableFrom(extensionType)) { - throw new XamlMarkupExtensionParseException("Unknown markup extension " + typeLocalName + "Extension in " + typeNamespaceUri); + throw new XamlMarkupExtensionParseException("Unknown markup extension " + typeName + "Extension"); } + if (extensionType == typeof(TypeExtension)) + extensionType = typeof(MyTypeExtension); + if (extensionType == typeof(System.Windows.StaticResourceExtension)) + extensionType = typeof(MyStaticResourceExtension); List positionalArgs = new List(); List> namedArgs = new List>(); @@ -280,10 +271,11 @@ namespace ICSharpCode.WpfDesign.XamlDom var ctorParameters = ctors[0].GetParameters(); object[] ctorArguments = new object[positionalArgs.Count]; for (int i = 0; i < ctorArguments.Length; i++) { - TypeConverter c = TypeDescriptor.GetConverter(ctorParameters[i].ParameterType); + Type parameterType = ctorParameters[i].ParameterType; + TypeConverter c = XamlNormalPropertyInfo.GetCustomTypeConverter(parameterType) + ?? TypeDescriptor.GetConverter(parameterType); ctorArguments[i] = XamlTextValue.AttributeTextToObject(positionalArgs[i], - containingElement, - document, + containingObject, c); } MarkupExtension result = (MarkupExtension)ctors[0].Invoke(ctorArguments); @@ -299,8 +291,7 @@ namespace ICSharpCode.WpfDesign.XamlDom throw new XamlMarkupExtensionParseException("Property not found: " + extensionType.FullName + "." + memberName); TypeConverter c = TypeDescriptor.GetConverter(property.PropertyType); object propValue = XamlTextValue.AttributeTextToObject(pair.Value, - containingElement, - document, + containingObject, c); property.SetValue(result, propValue, null); } @@ -308,12 +299,25 @@ namespace ICSharpCode.WpfDesign.XamlDom return result; } - sealed class TypeExtension : System.Windows.Markup.TypeExtension + sealed class MyTypeExtension : TypeExtension { - public TypeExtension() {} + public MyTypeExtension() {} + + public MyTypeExtension(string typeName) : base(typeName) {} + } + + sealed class MyStaticResourceExtension : System.Windows.StaticResourceExtension + { + public MyStaticResourceExtension() {} + + public MyStaticResourceExtension(object resourceKey) : base(resourceKey) {} - public TypeExtension(string typeName) : base(typeName) + public override object ProvideValue(IServiceProvider serviceProvider) { + XamlTypeResolverProvider xamlTypeResolver = (XamlTypeResolverProvider)serviceProvider.GetService(typeof(XamlTypeResolverProvider)); + if (xamlTypeResolver == null) + throw new XamlLoadException("XamlTypeResolverProvider not found."); + return xamlTypeResolver.FindResource(this.ResourceKey); } } } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/WpfDesign.XamlDom.csproj b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/WpfDesign.XamlDom.csproj index fd1f55425c..1f09b7f412 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/WpfDesign.XamlDom.csproj +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/WpfDesign.XamlDom.csproj @@ -77,5 +77,6 @@ + \ No newline at end of file diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlDocument.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlDocument.cs index 1cfdc4fc4a..e754cc5aca 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlDocument.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlDocument.cs @@ -7,6 +7,7 @@ using System; using System.ComponentModel; +using System.Windows.Markup; using System.Xml; namespace ICSharpCode.WpfDesign.XamlDom @@ -40,18 +41,29 @@ namespace ICSharpCode.WpfDesign.XamlDom get { return _serviceProvider; } } - internal ITypeDescriptorContext GetTypeDescriptorContext() + /// + /// Gets the type descriptor context used for type conversions. + /// + /// The containing object, used when the + /// type descriptor context needs to resolve an XML namespace. + internal ITypeDescriptorContext GetTypeDescriptorContext(XamlObject containingObject) { - return new DummyTypeDescriptorContext(this); + return new DummyTypeDescriptorContext(this, containingObject); } sealed class DummyTypeDescriptorContext : ITypeDescriptorContext { - XamlDocument document; + IServiceProvider baseServiceProvider; - public DummyTypeDescriptorContext(XamlDocument document) + public DummyTypeDescriptorContext(XamlDocument document, XamlObject containingObject) { - this.document = document; + if (containingObject != null) { + if (containingObject.OwnerDocument != document) + throw new ArgumentException("Containing object must belong to the document!"); + baseServiceProvider = new XamlTypeResolverProvider(containingObject); + } else { + baseServiceProvider = document.ServiceProvider; + } } public IContainer Container { @@ -77,7 +89,7 @@ namespace ICSharpCode.WpfDesign.XamlDom public object GetService(Type serviceType) { - return document.ServiceProvider.GetService(serviceType); + return baseServiceProvider.GetService(serviceType); } } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlObject.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlObject.cs index 8524a83b97..391e849165 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlObject.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlObject.cs @@ -59,6 +59,24 @@ namespace ICSharpCode.WpfDesign.XamlDom } #endregion + XamlObject parentObject; + + /// + /// Gets the parent object. + /// + public XamlObject ParentObject { + get { + return parentObject; + } + internal set { parentObject = value; } + } + + internal override void OnParentPropertyChanged() + { + parentObject = (ParentProperty != null) ? ParentProperty.ParentObject : null; + base.OnParentPropertyChanged(); + } + internal XmlElement XmlElement { get { return element; } } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs index e4bfbfac0e..53d4a27bf4 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs @@ -108,7 +108,12 @@ namespace ICSharpCode.WpfDesign.XamlDom Type FindType(string namespaceUri, string localName) { - Type elementType = settings.TypeFinder.GetType(namespaceUri, localName); + return FindType(settings.TypeFinder, namespaceUri, localName); + } + + static Type FindType(XamlTypeFinder typeFinder, string namespaceUri, string localName) + { + Type elementType = typeFinder.GetType(namespaceUri, localName); if (elementType == null) throw new XamlLoadException("Cannot find type " + localName + " in " + namespaceUri); return elementType; @@ -124,12 +129,14 @@ namespace ICSharpCode.WpfDesign.XamlDom readonly static object[] emptyObjectArray = new object[0]; XmlSpace currentXmlSpace = XmlSpace.None; + XamlObject currentXamlObject; XamlObject ParseObject(XmlElement element) { Type elementType = FindType(element.NamespaceURI, element.LocalName); XmlSpace oldXmlSpace = currentXmlSpace; + XamlObject parentXamlObject = currentXamlObject; if (element.HasAttribute("xml:space")) { currentXmlSpace = (XmlSpace)Enum.Parse(typeof(XmlSpace), element.GetAttribute("xml:space"), true); } @@ -160,7 +167,7 @@ namespace ICSharpCode.WpfDesign.XamlDom object instance; if (initializeFromTextValueInsteadOfConstructor != null) { instance = TypeDescriptor.GetConverter(elementType).ConvertFromString( - document.GetTypeDescriptorContext(), + document.GetTypeDescriptorContext(null), CultureInfo.InvariantCulture, initializeFromTextValueInsteadOfConstructor.Text); } else { @@ -168,6 +175,8 @@ namespace ICSharpCode.WpfDesign.XamlDom } XamlObject obj = new XamlObject(document, element, elementType, instance); + currentXamlObject = obj; + obj.ParentObject = parentXamlObject; ISupportInitialize iSupportInitializeInstance = instance as ISupportInitialize; if (iSupportInitializeInstance != null) { @@ -185,12 +194,28 @@ namespace ICSharpCode.WpfDesign.XamlDom ParseObjectAttribute(obj, attribute); } + if (!(obj.Instance is Style)) { + 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) + { XamlPropertyValue setDefaultValueTo = null; object defaultPropertyValue = null; XamlProperty defaultCollectionProperty = null; if (defaultProperty != null && defaultProperty.IsCollection && !element.IsEmpty) { - defaultPropertyValue = defaultProperty.GetValue(instance); + defaultPropertyValue = defaultProperty.GetValue(obj.Instance); obj.AddProperty(defaultCollectionProperty = new XamlProperty(obj, defaultProperty)); } @@ -200,7 +225,7 @@ namespace ICSharpCode.WpfDesign.XamlDom // here, but let's try to imitate it as good as possible if (defaultProperty != null && !defaultProperty.IsCollection) { for (; combinedNormalizedChildNodes > 0; combinedNormalizedChildNodes--) { - defaultProperty.GetValue(instance); + defaultProperty.GetValue(obj.Instance); } } @@ -213,7 +238,7 @@ namespace ICSharpCode.WpfDesign.XamlDom // I don't know why the official XamlReader runs the property getter // here, but let's try to imitate it as good as possible if (defaultProperty != null && !defaultProperty.IsCollection) { - defaultProperty.GetValue(instance); + defaultProperty.GetValue(obj.Instance); } ParseObjectChildElementAsPropertyElement(obj, childElement, defaultProperty, defaultPropertyValue); continue; @@ -224,8 +249,8 @@ namespace ICSharpCode.WpfDesign.XamlDom XamlPropertyValue childValue = ParseValue(childNode); if (childValue != null) { if (defaultProperty != null && defaultProperty.IsCollection) { - CollectionSupport.AddToCollection(defaultProperty.ReturnType, defaultPropertyValue, childValue); defaultCollectionProperty.ParserAddCollectionElement(null, childValue); + CollectionSupport.AddToCollection(defaultProperty.ReturnType, defaultPropertyValue, childValue); } else { if (setDefaultValueTo != null) throw new XamlLoadException("default property may have only one value assigned"); @@ -238,23 +263,15 @@ namespace ICSharpCode.WpfDesign.XamlDom { // Runs even when defaultValueSet==false! // Again, no idea why the official XamlReader does this. - defaultProperty.GetValue(instance); + defaultProperty.GetValue(obj.Instance); } if (setDefaultValueTo != null) { if (defaultProperty == null) { throw new XamlLoadException("This element does not have a default value, cannot assign to it"); } - defaultProperty.SetValue(instance, setDefaultValueTo.GetValueFor(defaultProperty)); obj.AddProperty(new XamlProperty(obj, defaultProperty, setDefaultValueTo)); + defaultProperty.SetValue(obj.Instance, setDefaultValueTo.GetValueFor(defaultProperty)); } - - if (iSupportInitializeInstance != null) { - iSupportInitializeInstance.EndInit(); - } - - currentXmlSpace = oldXmlSpace; - - return obj; } int combinedNormalizedChildNodes; @@ -319,7 +336,7 @@ namespace ICSharpCode.WpfDesign.XamlDom return null; } - static XamlPropertyInfo FindProperty(object elementInstance, Type propertyType, string propertyName) + internal static XamlPropertyInfo FindProperty(object elementInstance, Type propertyType, string propertyName) { PropertyDescriptorCollection properties; if (elementInstance != null) { @@ -375,17 +392,17 @@ namespace ICSharpCode.WpfDesign.XamlDom XamlPropertyInfo GetPropertyInfo(object elementInstance, Type elementType, XmlAttribute attribute) { if (attribute.LocalName.Contains(".")) { - return GetPropertyInfo(elementInstance, elementType, GetAttributeNamespace(attribute), attribute.LocalName); + return GetPropertyInfo(settings.TypeFinder, elementInstance, elementType, GetAttributeNamespace(attribute), attribute.LocalName); } else { return FindProperty(elementInstance, elementType, attribute.LocalName); } } - XamlPropertyInfo GetPropertyInfo(object elementInstance, Type elementType, string xmlNamespace, string localName) + internal static XamlPropertyInfo GetPropertyInfo(XamlTypeFinder typeFinder, object elementInstance, Type elementType, string xmlNamespace, string localName) { string typeName, propertyName; SplitQualifiedIdentifier(localName, out typeName, out propertyName); - Type propertyType = FindType(xmlNamespace, typeName); + Type propertyType = FindType(typeFinder, xmlNamespace, typeName); if (elementType == propertyType || propertyType.IsAssignableFrom(elementType)) { return FindProperty(elementInstance, propertyType, propertyName); } else { @@ -406,8 +423,8 @@ namespace ICSharpCode.WpfDesign.XamlDom { XamlPropertyInfo propertyInfo = GetPropertyInfo(obj.Instance, obj.ElementType, attribute); XamlTextValue textValue = new XamlTextValue(document, attribute); - propertyInfo.SetValue(obj.Instance, textValue.GetValueFor(propertyInfo)); obj.AddProperty(new XamlProperty(obj, propertyInfo, textValue)); + propertyInfo.SetValue(obj.Instance, textValue.GetValueFor(propertyInfo)); } static bool ObjectChildElementIsPropertyElement(XmlElement element) @@ -420,7 +437,7 @@ namespace ICSharpCode.WpfDesign.XamlDom Debug.Assert(element.LocalName.Contains(".")); // this is a element property syntax - XamlPropertyInfo propertyInfo = GetPropertyInfo(obj.Instance, obj.ElementType, element.NamespaceURI, element.LocalName); + XamlPropertyInfo propertyInfo = GetPropertyInfo(settings.TypeFinder, obj.Instance, obj.ElementType, element.NamespaceURI, element.LocalName); bool valueWasSet = false; object collectionInstance = null; @@ -458,10 +475,10 @@ namespace ICSharpCode.WpfDesign.XamlDom if (valueWasSet) throw new XamlLoadException("non-collection property may have only one child element"); valueWasSet = true; - propertyInfo.SetValue(obj.Instance, childValue.GetValueFor(propertyInfo)); XamlProperty xp = new XamlProperty(obj, propertyInfo, childValue); xp.ParserSetPropertyElement(element); obj.AddProperty(xp); + propertyInfo.SetValue(obj.Instance, childValue.GetValueFor(propertyInfo)); } } } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlPropertyInfo.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlPropertyInfo.cs index 104230c949..8282b9f550 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlPropertyInfo.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlPropertyInfo.cs @@ -42,6 +42,10 @@ namespace ICSharpCode.WpfDesign.XamlDom readonly DependencyProperty property; readonly bool isAttached; + public DependencyProperty Property { + get { return property; } + } + public XamlDependencyPropertyInfo(DependencyProperty property, bool isAttached) { Debug.Assert(property != null); @@ -101,7 +105,7 @@ namespace ICSharpCode.WpfDesign.XamlDom } } #endregion - + #region XamlNormalPropertyInfo internal sealed class XamlNormalPropertyInfo : XamlPropertyInfo { @@ -141,10 +145,7 @@ namespace ICSharpCode.WpfDesign.XamlDom public override TypeConverter TypeConverter { get { - if (_propertyDescriptor.PropertyType == typeof(object)) - return null; - else - return _propertyDescriptor.Converter; + return GetCustomTypeConverter(_propertyDescriptor.PropertyType) ?? _propertyDescriptor.Converter; } } @@ -167,6 +168,84 @@ namespace ICSharpCode.WpfDesign.XamlDom return CollectionSupport.IsCollectionType(_propertyDescriptor.PropertyType); } } + + public static readonly TypeConverter StringTypeConverter = TypeDescriptor.GetConverter(typeof(string)); + + public static TypeConverter GetCustomTypeConverter(Type propertyType) + { + if (propertyType == typeof(object)) + return StringTypeConverter; + else if (propertyType == typeof(Type)) + return TypeTypeConverter.Instance; + else if (propertyType == typeof(DependencyProperty)) + return DependencyPropertyConverter.Instance; + else + return null; + } + + sealed class TypeTypeConverter : TypeConverter + { + public readonly static TypeTypeConverter Instance = new TypeTypeConverter(); + + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + return true; + else + return base.CanConvertFrom(context, sourceType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value == null) + return null; + if (value is string) { + IXamlTypeResolver xamlTypeResolver = (IXamlTypeResolver)context.GetService(typeof(IXamlTypeResolver)); + if (xamlTypeResolver == null) + throw new XamlLoadException("IXamlTypeResolver not found in type descriptor context."); + return xamlTypeResolver.Resolve((string)value); + } else { + return base.ConvertFrom(context, culture, value); + } + } + } + + sealed class DependencyPropertyConverter : TypeConverter + { + public readonly static DependencyPropertyConverter Instance = new DependencyPropertyConverter(); + + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + return true; + else + return base.CanConvertFrom(context, sourceType); + } + + 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.Property; + 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); + } + } + } } #endregion @@ -208,7 +287,7 @@ namespace ICSharpCode.WpfDesign.XamlDom } public override TypeConverter TypeConverter { - get { return null; } + get { return XamlNormalPropertyInfo.StringTypeConverter; } } public override string FullyQualifiedName { diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlTextValue.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlTextValue.cs index 42309c49fe..a967ad50d9 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlTextValue.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlTextValue.cs @@ -109,83 +109,40 @@ namespace ICSharpCode.WpfDesign.XamlDom return b.ToString(); } - static readonly TypeConverter stringTypeConverter = TypeDescriptor.GetConverter(typeof(string)); - internal override object GetValueFor(XamlPropertyInfo targetProperty) { + if (ParentProperty == null) + throw new InvalidOperationException("Cannot call GetValueFor while ParentProperty is null"); if (attribute != null) { - return AttributeTextToObject(attribute.Value, attribute.OwnerElement, document, - targetProperty != null ? targetProperty.TypeConverter : stringTypeConverter); + return AttributeTextToObject(attribute.Value, ParentProperty.ParentObject, + targetProperty != null ? targetProperty.TypeConverter : XamlNormalPropertyInfo.StringTypeConverter); } if (targetProperty == null) return this.Text; - TypeConverter converter = targetProperty.TypeConverter; - if (converter != null) { - return converter.ConvertFromString(document.GetTypeDescriptorContext(), CultureInfo.InvariantCulture, this.Text); - } else { - return this.Text; - } + return targetProperty.TypeConverter.ConvertFromString( + document.GetTypeDescriptorContext(ParentProperty.ParentObject), + CultureInfo.InvariantCulture, this.Text); } - internal static object AttributeTextToObject(string attributeText, XmlElement containingElement, - XamlDocument document, TypeConverter typeConverter) + internal static object AttributeTextToObject(string attributeText, XamlObject containingObject, + TypeConverter typeConverter) { - if (typeConverter == null) - typeConverter = stringTypeConverter; if (attributeText.StartsWith("{}")) { return typeConverter.ConvertFromString( - document.GetTypeDescriptorContext(), CultureInfo.InvariantCulture, + containingObject.OwnerDocument.GetTypeDescriptorContext(containingObject), CultureInfo.InvariantCulture, attributeText.Substring(2)); } else if (attributeText.StartsWith("{")) { - XamlTypeResolverProvider xtrp = new XamlTypeResolverProvider(document, containingElement, document.ServiceProvider); + XamlTypeResolverProvider xtrp = new XamlTypeResolverProvider(containingObject); MarkupExtension extension = MarkupExtensionParser.ConstructMarkupExtension( - attributeText, containingElement, document); + attributeText, containingObject, xtrp); return extension.ProvideValue(xtrp); } else { return typeConverter.ConvertFromString( - document.GetTypeDescriptorContext(), CultureInfo.InvariantCulture, + containingObject.OwnerDocument.GetTypeDescriptorContext(containingObject), CultureInfo.InvariantCulture, attributeText); } } - sealed class XamlTypeResolverProvider : IXamlTypeResolver, IServiceProvider - { - XamlDocument document; - XmlElement containingElement; - IServiceProvider baseProvider; - - public XamlTypeResolverProvider(XamlDocument document, XmlElement containingElement, IServiceProvider baseProvider) - { - this.document = document; - this.containingElement = containingElement; - this.baseProvider = baseProvider; - } - - public Type Resolve(string typeName) - { - string typeNamespaceUri; - string typeLocalName; - if (typeName.Contains(":")) { - typeNamespaceUri = containingElement.GetNamespaceOfPrefix(typeName.Substring(0, typeName.IndexOf(':'))); - typeLocalName = typeName.Substring(typeName.IndexOf(':') + 1); - } else { - typeNamespaceUri = containingElement.NamespaceURI; - typeLocalName = typeName; - } - if (string.IsNullOrEmpty(typeNamespaceUri)) - throw new XamlMarkupExtensionParseException("Unrecognized namespace prefix in type " + typeName); - return document.TypeFinder.GetType(typeNamespaceUri, typeLocalName); - } - - public object GetService(Type serviceType) - { - if (serviceType == typeof(IXamlTypeResolver)) - return this; - else - return baseProvider.GetService(serviceType); - } - } - internal override void RemoveNodeFromParent() { if (attribute != null) diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlTypeResolverProvider.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlTypeResolverProvider.cs new file mode 100644 index 0000000000..b1a19250f2 --- /dev/null +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlTypeResolverProvider.cs @@ -0,0 +1,102 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.Text; +using System.Windows; +using System.Windows.Markup; +using System.Xml; + +namespace ICSharpCode.WpfDesign.XamlDom +{ + sealed class XamlTypeResolverProvider : IXamlTypeResolver, IServiceProvider + { + XamlDocument document; + XamlObject containingObject; + XmlElement containingElement; + + public XamlTypeResolverProvider(XamlObject containingObject) + { + if (containingObject == null) + throw new ArgumentNullException("containingObject"); + this.document = containingObject.OwnerDocument; + this.containingObject = containingObject; + this.containingElement = containingObject.XmlElement; + } + + public Type Resolve(string typeName) + { + string typeNamespaceUri; + string typeLocalName; + if (typeName.Contains(":")) { + typeNamespaceUri = containingElement.GetNamespaceOfPrefix(typeName.Substring(0, typeName.IndexOf(':'))); + typeLocalName = typeName.Substring(typeName.IndexOf(':') + 1); + } else { + typeNamespaceUri = containingElement.NamespaceURI; + typeLocalName = typeName; + } + if (string.IsNullOrEmpty(typeNamespaceUri)) + throw new XamlMarkupExtensionParseException("Unrecognized namespace prefix in type " + typeName); + return document.TypeFinder.GetType(typeNamespaceUri, typeLocalName); + } + + public object GetService(Type serviceType) + { + if (serviceType == typeof(IXamlTypeResolver) || serviceType == typeof(XamlTypeResolverProvider)) + return this; + else + return document.ServiceProvider.GetService(serviceType); + } + + public XamlPropertyInfo ResolveProperty(string propertyName) + { + string propertyNamespace; + if (propertyName.Contains(":")) { + propertyNamespace = containingElement.GetNamespaceOfPrefix(propertyName.Substring(0, propertyName.IndexOf(':'))); + propertyName = propertyName.Substring(propertyName.IndexOf(':') + 1); + } else { + propertyNamespace = containingElement.NamespaceURI; + } + Type elementType = null; + XamlObject obj = containingObject; + while (obj != null) { + Style style = obj.Instance as Style; + if (style != null && style.TargetType != null) { + elementType = style.TargetType; + break; + } + obj = obj.ParentObject; + } + if (propertyName.Contains(".")) { + return XamlParser.GetPropertyInfo(document.TypeFinder, null, elementType, propertyNamespace, propertyName); + } else if (elementType != null) { + return XamlParser.FindProperty(null, elementType, propertyName); + } else { + return null; + } + } + + public object FindResource(object key) + { + XamlObject obj = containingObject; + while (obj != null) { + FrameworkElement el = obj.Instance as FrameworkElement; + if (el != null) { + object val = el.Resources[key]; + if (val != null) + return val; + } + obj = obj.ParentObject; + } + return null; + } + } +}