Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / System / Windows / Markup / Primitives / ElementMarkupObject.cs / 2 / ElementMarkupObject.cs
//------------------------------------------------------------------------ // // Microsoft Windows Client Platform // Copyright (c) Microsoft Corporation. All rights reserved. // // File: ElementMarkupObject.cs // // Contents: MarkupObject and MarkupProperty implementation for // DependencyObject // // Created: 04/28/2005 [....] // // // Class hierarchy in this file: // // (MarkupObject) // ElementMarkupObject // // (MarkupProperty) // ElementPropertyBase // ElementObjectPropertyBase // ElementProperty // ElementPseudoPropertyBase // ElementKey // ElementConstructorArgument // ElementItemsPseudoProperty // ElementDictionaryItemsPseudoProperty // ElementStringValueProperty // //----------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Text; using System.Windows; using System.Windows.Data; using System.Windows.Markup; using System.Windows.Documents; namespace System.Windows.Markup.Primitives { ////// An implementation of MarkupObject for DependencyObjects that works also for CLR only objects /// internal class ElementMarkupObject : MarkupObject { internal ElementMarkupObject(object instance, XamlDesignerSerializationManager manager) { Debug.Assert(instance != null); _instance = instance; _context = new ElementObjectContext(this, null); _manager = manager; } public override Type ObjectType { get { return _instance.GetType(); } } public override object Instance { get { return _instance; } } internal override IEnumerableGetProperties(bool mapToConstructorArgs) { ValueSerializer valueSerializer = ValueSerializer.GetSerializerFor(ObjectType, Context); if (valueSerializer != null && valueSerializer.CanConvertToString(_instance, Context)) { yield return new ElementStringValueProperty(this); if (_key != null) { yield return _key; } } else { Dictionary constructorArguments = null; // if this markup item is the value of property in attribute form and the instance // it represents is a MarkupExtension, then we return any properties that are // constructor arguments as ElementConstructorArgument markup properties if (mapToConstructorArgs && _instance is MarkupExtension) { // Detect if the instance should be constructed using constructor parameters by // seeing if it can be converted to an instance descriptor that uses a constructor. TypeConverter converter = TypeDescriptor.GetConverter(_instance); if (converter != null && converter.CanConvertTo(Context, typeof(InstanceDescriptor))) { InstanceDescriptor instanceDescriptor; try { instanceDescriptor = converter.ConvertTo(_context, System.Windows.Markup.TypeConverterHelper.EnglishUSCulture, _instance, typeof(InstanceDescriptor)) as InstanceDescriptor; } catch (InvalidOperationException) { // If we get this just ignore the converter instanceDescriptor = null; } catch (NotSupportedException) { // If we get this just ignore the converter instanceDescriptor = null; } if (instanceDescriptor != null) { ConstructorInfo ctorInfo = instanceDescriptor.MemberInfo as ConstructorInfo; if (ctorInfo != null) { ParameterInfo[] parameters = ctorInfo.GetParameters(); if (parameters != null && parameters.Length == instanceDescriptor.Arguments.Count) { int i = 0; foreach (object value in instanceDescriptor.Arguments) { if (constructorArguments == null) { constructorArguments = new Dictionary (); } // store a list of the parameters that are constructor arguments // so that we don't return those properties again constructorArguments.Add(parameters[i].Name, parameters[i].Name); yield return new ElementConstructorArgument(value, parameters[i++].ParameterType, this); } } } } } } foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(_instance)) { DesignerSerializationVisibility visibility = descriptor.SerializationVisibility; if (visibility != DesignerSerializationVisibility.Hidden && (!descriptor.IsReadOnly || visibility == DesignerSerializationVisibility.Content) && ShouldSerialize(descriptor, _instance, _manager)) { if (visibility == DesignerSerializationVisibility.Content) { // Ensure the collection has content object value = descriptor.GetValue(_instance); if (value == null) { continue; } else { ICollection collection = value as ICollection; if (collection != null && collection.Count < 1) { continue; } IEnumerable enumerable = value as IEnumerable; if (enumerable != null && !enumerable.GetEnumerator().MoveNext()) { continue; } } } if (constructorArguments != null) { ConstructorArgumentAttribute constructorArgumentAttribute = descriptor.Attributes[typeof(ConstructorArgumentAttribute)] as ConstructorArgumentAttribute; if (constructorArgumentAttribute != null && constructorArguments.ContainsKey(constructorArgumentAttribute.ArgumentName)) { // Skip this property, it has already been represented by a constructor parameter continue; } } yield return new ElementProperty(this, descriptor); } } IDictionary dictionary = _instance as IDictionary; if (dictionary != null) { yield return new ElementDictionaryItemsPseudoProperty(dictionary, typeof(IDictionary), this); } else { IEnumerable enumerable = _instance as IEnumerable; if (enumerable != null && enumerable.GetEnumerator().MoveNext()) { yield return new ElementItemsPseudoProperty(enumerable, typeof(IEnumerable), this); } } if (_key != null) { yield return _key; } } } public override AttributeCollection Attributes { get { return TypeDescriptor.GetAttributes(ObjectType); } } public override void AssignRootContext(IValueSerializerContext context) { _context = new ElementObjectContext(this, context); } internal IValueSerializerContext Context { get { return _context; } } internal XamlDesignerSerializationManager Manager { get { return _manager; } } internal void SetKey(ElementKey key) { _key = key; } private sealed class ElementObjectContext : ValueSerializerContextWrapper, IValueSerializerContext { ElementMarkupObject _object; public ElementObjectContext(ElementMarkupObject obj, IValueSerializerContext baseContext): base(baseContext) { _object = obj; } object ITypeDescriptorContext.Instance { get { return _object.Instance; } } } private static bool ShouldSerialize(PropertyDescriptor pd, object instance, XamlDesignerSerializationManager manager) { MethodInfo shouldSerializeMethod; object invokeInstance = instance; DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(pd); if (dpd != null && dpd.IsAttached) { Type ownerType = dpd.DependencyProperty.OwnerType; string propertyName = dpd.DependencyProperty.Name; string keyName = propertyName + "!"; if (!TryGetShouldSerializeMethod(new ShouldSerializeKey(ownerType, keyName), out shouldSerializeMethod)) { string methodName = "ShouldSerialize" + propertyName; shouldSerializeMethod = ownerType.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsObject, null); if (shouldSerializeMethod == null) shouldSerializeMethod = ownerType.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsManager, null); if (shouldSerializeMethod == null) shouldSerializeMethod = ownerType.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsMode, null); if (shouldSerializeMethod == null) shouldSerializeMethod = ownerType.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsObjectManager, null); if (shouldSerializeMethod != null && shouldSerializeMethod.ReturnType != typeof(bool)) shouldSerializeMethod = null; CacheShouldSerializeMethod(new ShouldSerializeKey(ownerType, keyName), shouldSerializeMethod); } invokeInstance = null; // static method } else { if (!TryGetShouldSerializeMethod(new ShouldSerializeKey(instance.GetType(), pd.Name), out shouldSerializeMethod)) { Type instanceType = instance.GetType(); string methodName = "ShouldSerialize" + pd.Name; shouldSerializeMethod = instanceType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsObject, null); if (shouldSerializeMethod == null) shouldSerializeMethod = instanceType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsManager, null); if (shouldSerializeMethod == null) shouldSerializeMethod = instanceType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsMode, null); if (shouldSerializeMethod == null) shouldSerializeMethod = instanceType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsObjectManager, null); if (shouldSerializeMethod != null && shouldSerializeMethod.ReturnType != typeof(bool)) shouldSerializeMethod = null; CacheShouldSerializeMethod(new ShouldSerializeKey(instanceType, pd.Name), shouldSerializeMethod); } } if (shouldSerializeMethod != null) { ParameterInfo[] parameters = shouldSerializeMethod.GetParameters(); if (parameters != null) { object[] args; if (parameters.Length == 1) { if (parameters[0].ParameterType == typeof(DependencyObject)) { args = new object[] { instance as DependencyObject }; } else if (parameters[0].ParameterType == typeof(XamlWriterMode)) { args = new object[] { manager.XamlWriterMode }; } else { args = new object[] { manager }; } } else args = new object[] { instance as DependencyObject, manager }; return (bool)shouldSerializeMethod.Invoke(invokeInstance, args); } } return pd.ShouldSerializeValue(instance); } private struct ShouldSerializeKey { public ShouldSerializeKey(Type type, string propertyName) { _type = type; _propertyName = propertyName; } public override bool Equals(object obj) { if (!(obj is ShouldSerializeKey)) return false; ShouldSerializeKey other = (ShouldSerializeKey)obj; return other._type == _type && other._propertyName == _propertyName; } /// /// Forward to .Equals /// public static bool operator ==(ShouldSerializeKey key1, ShouldSerializeKey key2) { return key1.Equals(key2); } ////// Forward to .Equals /// public static bool operator !=(ShouldSerializeKey key1, ShouldSerializeKey key2) { return !(key1.Equals(key2)); } public override int GetHashCode() { return _type.GetHashCode() ^ _propertyName.GetHashCode(); } private Type _type; private string _propertyName; } private static bool TryGetShouldSerializeMethod(ShouldSerializeKey key, out MethodInfo methodInfo) { object value = _shouldSerializeCache[key]; if (value == null || value == _shouldSerializeCacheLock) { // The _shouldSerializeCacheLock is used as a sentinal for null methodInfo = null; return value != null; } else { methodInfo = value as MethodInfo; return true; } } private static void CacheShouldSerializeMethod(ShouldSerializeKey key, MethodInfo methodInfo) { // The instance stored in _shouldSerializeCacheLock is used as a sentinal for null // The avoids having to perform two lookups in the Hashtable to detect a cached null value. object value = methodInfo == null ? _shouldSerializeCacheLock : methodInfo; lock (_shouldSerializeCacheLock) { _shouldSerializeCache[key] = value; } } private static object _shouldSerializeCacheLock = new object(); private static Hashtable _shouldSerializeCache = new Hashtable(); private static Type[] _shouldSerializeArgsObject = new Type[] { typeof(DependencyObject) }; private static Type[] _shouldSerializeArgsManager = new Type[] { typeof(XamlDesignerSerializationManager) }; private static Type[] _shouldSerializeArgsMode = new Type[] { typeof(XamlWriterMode) }; private static Type[] _shouldSerializeArgsObjectManager = new Type[] { typeof(DependencyObject), typeof(XamlDesignerSerializationManager) }; private static Attribute[] _propertyAttributes = new Attribute[] { new PropertyFilterAttribute(PropertyFilterOptions.SetValues) }; private object _instance; private IValueSerializerContext _context; private ElementKey _key; private XamlDesignerSerializationManager _manager; } internal abstract class ElementPropertyBase : MarkupProperty { public ElementPropertyBase(XamlDesignerSerializationManager manager) { _manager = manager; } public override bool IsComposite { get { if (!_isCompositeCalculated) { _isCompositeCalculated = true; object value = Value; if (value == null) { _isComposite = true; } else if (value is string && PropertyType.IsAssignableFrom(typeof(object))) { _isComposite = false; } else if (value is MarkupExtension) { _isComposite = true; } else { _isComposite = !CanConvertToString(value); } } return _isComposite; } } public override string StringValue { get { if (IsComposite) { return String.Empty; } object value = Value; string stringValue = value as string; if (stringValue != null) { return stringValue; } ValueSerializer serializer = GetValueSerializer(); if (serializer == null) { return String.Empty; } return serializer.ConvertToString(value, Context); } } public override IEnumerableItems { get { object value = Value; if (value != null) { if (PropertyDescriptor != null && (PropertyDescriptor.IsReadOnly || (!PropertyIsAttached(PropertyDescriptor) && PropertyType == value.GetType() && // These types the serializer will synthesize a start element when // reading them in (typeof(IList).IsAssignableFrom(PropertyType) || typeof(IDictionary).IsAssignableFrom(PropertyType) || typeof(Freezable).IsAssignableFrom(PropertyType) || typeof(FrameworkElementFactory).IsAssignableFrom(PropertyType))) && HasNoSerializableProperties(value) && !IsEmpty(value))) { IDictionary dictionary = value as IDictionary; if (dictionary != null) { Type keyType = GetDictionaryKeyType(dictionary); // Attempt to emit the contents of the dictionary in a more deterministic // order. This is not guarenteed to be deterministic because it uses ToString // which is not guarenteed to be unique for each value. Keys with non-unique // ToString() values will not be emitted deterministically. DictionaryEntry[] entries = new DictionaryEntry[dictionary.Count]; dictionary.CopyTo(entries, 0); Array.Sort(entries, delegate(DictionaryEntry one, DictionaryEntry two) { return String.Compare(one.Key.ToString(), two.Key.ToString()); }); foreach (DictionaryEntry entry in entries) { ElementMarkupObject subItem = new ElementMarkupObject( ElementProperty.CheckForMarkupExtension(typeof(Object), entry.Value, Context, false), Manager); subItem.SetKey(new ElementKey(entry.Key, keyType, subItem)); yield return subItem; } } else { IEnumerable items = value as IEnumerable; if (items != null) { foreach (object o in items) { MarkupObject subItem = new ElementMarkupObject( ElementProperty.CheckForMarkupExtension(typeof(Object), o, Context, false), Manager); yield return subItem; } } else { if (PropertyType == typeof(FrameworkElementFactory) && value is FrameworkElementFactory) { MarkupObject subItem = new FrameworkElementFactoryMarkupObject(value as FrameworkElementFactory, Manager); yield return subItem; } else { MarkupObject subItem = new ElementMarkupObject( ElementProperty.CheckForMarkupExtension(typeof(Object), value, Context, true), Manager); yield return subItem; } } } } else { MarkupObject subItem = new ElementMarkupObject( ElementProperty.CheckForMarkupExtension(typeof(Object), value, Context, true), Manager); yield return subItem; } } else { MarkupObject subItem = new ElementMarkupObject(new System.Windows.Markup.NullExtension(), Manager); yield return subItem; } } } private bool PropertyIsAttached(PropertyDescriptor descriptor) { DependencyPropertyDescriptor dependencyPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(PropertyDescriptor); return dependencyPropertyDescriptor != null && dependencyPropertyDescriptor.IsAttached; } private bool HasNoSerializableProperties(object value) { if (value is FrameworkElementFactory) return true; ElementMarkupObject item = new ElementMarkupObject(value, Manager); foreach (MarkupProperty property in item.Properties) { if (!property.IsContent) { return false; } } return true; } private bool IsEmpty(object value) { IEnumerable collection = value as IEnumerable; if (collection != null) { foreach (object o in collection) return false; return true; } return false; } protected IValueSerializerContext Context { get { if (_context == null) { _context = new ElementPropertyContext(this, GetItemContext()); } return _context; } } internal XamlDesignerSerializationManager Manager { get { return _manager; } } static readonly List EmptyTypes = new List (); public override IEnumerable TypeReferences { get { ValueSerializer serializer = GetValueSerializer(); if (serializer == null) return EmptyTypes; else return serializer.TypeReferences(Value, Context); } } protected bool CanConvertToString( object value ) { // See if this value can be converted to a string by a value serializer or type converter if( value == null ) { return false; } ValueSerializer serializer = GetValueSerializer(); return serializer != null && serializer.CanConvertToString(value, Context); } protected abstract IValueSerializerContext GetItemContext(); protected abstract Type GetObjectType(); private sealed class ElementPropertyContext : ValueSerializerContextWrapper, IValueSerializerContext { ElementPropertyBase _property; public ElementPropertyContext(ElementPropertyBase property, IValueSerializerContext baseContext) : base(baseContext) { _property = property; } PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor { get { return _property.PropertyDescriptor; } } } private ValueSerializer GetValueSerializer() { PropertyDescriptor descriptor = this.PropertyDescriptor; if (descriptor == null) { DependencyProperty property = this.DependencyProperty; if (property != null) descriptor = DependencyPropertyDescriptor.FromProperty(property, GetObjectType()); } if (descriptor != null) return ValueSerializer.GetSerializerFor(descriptor, GetItemContext()); else return ValueSerializer.GetSerializerFor(PropertyType, GetItemContext()); } private static Dictionary _keyTypeMap; private static Type GetDictionaryKeyType(IDictionary value) { Type type = value.GetType(); Type result; if (_keyTypeMap == null) _keyTypeMap = new Dictionary (); if (!_keyTypeMap.TryGetValue(type, out result)) { foreach (Type interfaceType in type.GetInterfaces()) { if (interfaceType.IsGenericType) { Type genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(System.Collections.Generic.IDictionary<,>)) return interfaceType.GetGenericArguments()[0]; } } result = typeof(object); _keyTypeMap[type] = result; } return result; } private bool _isComposite; private bool _isCompositeCalculated; private IValueSerializerContext _context; private XamlDesignerSerializationManager _manager; } internal abstract class ElementObjectPropertyBase : ElementPropertyBase { protected ElementObjectPropertyBase(ElementMarkupObject obj): base(obj.Manager) { Debug.Assert(obj != null); _object = obj; } protected override IValueSerializerContext GetItemContext() { return _object.Context; } protected override Type GetObjectType() { return _object.ObjectType; } protected readonly ElementMarkupObject _object; } /// /// An implementation of MarkupProperty for DependencyObjects that works also for CLR only objects /// internal class ElementProperty : ElementObjectPropertyBase { internal ElementProperty(ElementMarkupObject obj, PropertyDescriptor descriptor) : base(obj) { Debug.Assert(descriptor != null); _descriptor = descriptor; } public override string Name { get { return _descriptor.Name; } } public override Type PropertyType { get { return _descriptor.PropertyType; } } public override PropertyDescriptor PropertyDescriptor { get { return _descriptor; } } public override bool IsAttached { get { UpdateDependencyProperty(); return _isAttached; } } public override DependencyProperty DependencyProperty { get { UpdateDependencyProperty(); return _dependencyProperty; } } public override object Value { get { object value; DependencyProperty DP = DependencyProperty; // For DPs, we use ReadLocalValue to find the property, and handle // unset values. if (DP != null) { DependencyObject DO = _object.Instance as DependencyObject; Debug.Assert(DO != null); // get the local value of the DP value = DO.ReadLocalValue(DP); // Expressions require special handling Expression expression = value as Expression; if (expression != null) { // Special-case: Expressions always get converted to an ME if // possible (and requested), and get de-referenced otherwise. TypeConverter converter = TypeDescriptor.GetConverter(value); if (Manager.XamlWriterMode == XamlWriterMode.Expression && converter.CanConvertTo(typeof(MarkupExtension))) { value = converter.ConvertTo(expression, typeof(MarkupExtension)); } else { value = expression.GetValue(DO, DP); } } // If the expression gave us UnsetValue, fall back to the default. if (value == DependencyProperty.UnsetValue) { value = DP.GetDefaultValue(DO.DependencyObjectType); } } // If this is the VisualTree property of a template, we have to do special processing. // Long-term plan is to replace this with an attribute on the type, that tells us how // to serialize its content. else if (Name == "VisualTree" && Context.Instance is FrameworkTemplate && (Context.Instance as FrameworkTemplate).HasContent ) { // Instantiate the template, in un-optimized form. This makes the template content // load as if it were loaded from xaml outside a template. The only exception is that // TemplateBinding's will show up as a TemplateBindingExtension. value = (Context.Instance as FrameworkTemplate).LoadContent(); } // Otherwise, get the value from the property descriptor. else { value = _descriptor.GetValue(_object.Instance); } // Convert the resulting value from above into a MarkupExtension, if necessary/possible, // but only if there is no value serializer; if the type supports conversion to both // string and ME, we give preference to the string conversion. if( !(value is MarkupExtension) && !CanConvertToString(value) ) { value = CheckForMarkupExtension(PropertyType, value, Context, true); } return value; } } public override AttributeCollection Attributes { get { return _descriptor.Attributes; } } private void UpdateDependencyProperty() { if (!_isDependencyPropertyCached) { DependencyPropertyDescriptor dpDesc = DependencyPropertyDescriptor.FromProperty(_descriptor); if (dpDesc != null) { _dependencyProperty = dpDesc.DependencyProperty; _isAttached = dpDesc.IsAttached; } _isDependencyPropertyCached = true; } } // // Check for values that can be converted into markup extensions, either because // they are a well known type ((null, arrays, enums, and types), or because they // can be type converted into an ME. // internal static object CheckForMarkupExtension( Type propertyType, object value, IValueSerializerContext context, bool convertEnums) { // null => NullExtension if (value == null) { return new NullExtension(); } // See if the type has a type converter that can create a MarkupExtension // (Have to do this after the null check so that GetConverter doesn't get // an invalid argument.) TypeConverter converter = TypeDescriptor.GetConverter(value); if (converter.CanConvertTo(context, typeof(MarkupExtension))) { // The type provides a converter that creates a MarkupExtension. return converter.ConvertTo(context, System.Windows.Markup.TypeConverterHelper.EnglishUSCulture, value, typeof(MarkupExtension)); } // System.Type => TypeExtension Type type = value as Type; if (type != null) { // If the property is declared to be a type already, we don't need to convert it // into {x:Type} syntax. if( propertyType == typeof(Type) ) { return value; } return new TypeExtension(type); } // Enums => StaticExtension if (convertEnums) { Enum enumValue = value as Enum; if (enumValue != null) { ValueSerializer typeSerializer = context.GetValueSerializerFor(typeof(Type)); Debug.Assert(typeSerializer != null, "typeSerializer for Enum was null"); string typeName = typeSerializer.ConvertToString(enumValue.GetType(), context); return new StaticExtension(typeName + "." + enumValue.ToString()); } } // Arrays => ArrayExtension Array array = value as Array; if (array != null) { return new ArrayExtension(array); } // Otherwise, value is unchanged. return value; } private PropertyDescriptor _descriptor; private bool _isDependencyPropertyCached; private DependencyProperty _dependencyProperty; private bool _isAttached; } ////// Pseudo-property for strings passed to a type converter /// internal class ElementStringValueProperty : MarkupProperty { internal ElementStringValueProperty(ElementMarkupObject obj) { _object = obj; } public override string Name { get { return "StringValue"; } } public override Type PropertyType { get { return typeof(string); } } public override bool IsValueAsString { get { return true; } } public override object Value { get { return StringValue; } } public override string StringValue { get { ValueSerializer serializer = ValueSerializer.GetSerializerFor(_object.ObjectType, _object.Context); Debug.Assert(serializer != null && serializer.CanConvertToString(_object.Instance, _object.Context), "StringValue property value created for a type that cannot be converted to string"); return serializer.ConvertToString(_object.Instance, _object.Context); } } public override IEnumerableItems { get { Debug.WriteLine("ElementMarkupObject.Items is not implemented"); return null; } } public override AttributeCollection Attributes { get { return AttributeCollection.Empty; } } public override IEnumerable TypeReferences { get { ValueSerializer serializer = ValueSerializer.GetSerializerFor(_object.ObjectType, _object.Context); Debug.Assert(serializer != null && serializer.CanConvertToString(_object.Instance, _object.Context), "StringValue property value created for a type that cannot be converted to string"); return serializer.TypeReferences(_object.Instance, _object.Context); } } private ElementMarkupObject _object; } /// /// Pseudo-property for the key of a dictionary element /// internal abstract class ElementPseudoPropertyBase : ElementObjectPropertyBase { internal ElementPseudoPropertyBase(object value, Type type, ElementMarkupObject obj) : base(obj) { _value = value; _type = type; } public override Type PropertyType { get { return _type; } } public override object Value { get { return ElementProperty.CheckForMarkupExtension(PropertyType, _value, Context, true /*convertEnums*/); } } public override AttributeCollection Attributes { get { return AttributeCollection.Empty; } } public override IEnumerableTypeReferences { get { return new Type[0]; } } private object _value; private Type _type; } /// /// Pseudo-property for the key of a dictionary element /// internal class ElementKey : ElementPseudoPropertyBase { internal ElementKey(object value, Type type, ElementMarkupObject obj) : base(value, type, obj) { } public override string Name { get { return "Key"; } } public override bool IsKey { get { return true; } } } ////// Pseudo-property for constructor arguments /// internal class ElementConstructorArgument : ElementPseudoPropertyBase { internal ElementConstructorArgument(object value, Type type, ElementMarkupObject obj) : base(value, type, obj) { } public override string Name { get { return "Argument"; } } public override bool IsConstructorArgument { get { return true; } } } ////// Pseudo-property for IEnumerable implementations /// internal class ElementItemsPseudoProperty : ElementPseudoPropertyBase { internal ElementItemsPseudoProperty(IEnumerable value, Type type, ElementMarkupObject obj) : base(value, type, obj) { _value = value; } public override string Name { get { return "Items"; } } public override bool IsContent { get { return true; } } public override bool IsComposite { get { return true; } } public override IEnumerableItems { get { foreach (object instance in _value) { yield return new ElementMarkupObject(instance, Manager); } } } IEnumerable _value; } /// /// Pseudo-property for IDictionary implementation /// internal class ElementDictionaryItemsPseudoProperty : ElementPseudoPropertyBase { internal ElementDictionaryItemsPseudoProperty(IDictionary value, Type type, ElementMarkupObject obj) : base(value, type, obj) { _value = value; } public override string Name { get { return "Entries"; } } public override bool IsContent { get { return true; } } public override bool IsComposite { get { return true; } } public override IEnumerableItems { get { foreach (DictionaryEntry entry in _value) { ElementMarkupObject item = new ElementMarkupObject(entry.Value, Manager); item.SetKey(new ElementKey(entry.Key, typeof(object), item)); yield return item; } } } IDictionary _value; } internal class ValueSerializerContextWrapper : IValueSerializerContext { IValueSerializerContext _baseContext; public ValueSerializerContextWrapper(IValueSerializerContext baseContext) { _baseContext = baseContext; } public ValueSerializer GetValueSerializerFor(PropertyDescriptor descriptor) { if (_baseContext != null) return _baseContext.GetValueSerializerFor(descriptor); else return null; } public ValueSerializer GetValueSerializerFor(Type type) { if (_baseContext != null) return _baseContext.GetValueSerializerFor(type); else return null; } public IContainer Container { get { if (_baseContext != null) return _baseContext.Container; else return null; } } public object Instance { get { if (_baseContext != null) return _baseContext.Instance; else return null; } } public void OnComponentChanged() { if (_baseContext != null) _baseContext.OnComponentChanged(); } public bool OnComponentChanging() { if (_baseContext != null) return _baseContext.OnComponentChanging(); else return true; } public PropertyDescriptor PropertyDescriptor { get { if (_baseContext != null) return _baseContext.PropertyDescriptor; else return null; } } public object GetService(Type serviceType) { if (_baseContext != null) return _baseContext.GetService(serviceType); else return null; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------ // // Microsoft Windows Client Platform // Copyright (c) Microsoft Corporation. All rights reserved. // // File: ElementMarkupObject.cs // // Contents: MarkupObject and MarkupProperty implementation for // DependencyObject // // Created: 04/28/2005 [....] // // // Class hierarchy in this file: // // (MarkupObject) // ElementMarkupObject // // (MarkupProperty) // ElementPropertyBase // ElementObjectPropertyBase // ElementProperty // ElementPseudoPropertyBase // ElementKey // ElementConstructorArgument // ElementItemsPseudoProperty // ElementDictionaryItemsPseudoProperty // ElementStringValueProperty // //----------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Text; using System.Windows; using System.Windows.Data; using System.Windows.Markup; using System.Windows.Documents; namespace System.Windows.Markup.Primitives { /// /// An implementation of MarkupObject for DependencyObjects that works also for CLR only objects /// internal class ElementMarkupObject : MarkupObject { internal ElementMarkupObject(object instance, XamlDesignerSerializationManager manager) { Debug.Assert(instance != null); _instance = instance; _context = new ElementObjectContext(this, null); _manager = manager; } public override Type ObjectType { get { return _instance.GetType(); } } public override object Instance { get { return _instance; } } internal override IEnumerableGetProperties(bool mapToConstructorArgs) { ValueSerializer valueSerializer = ValueSerializer.GetSerializerFor(ObjectType, Context); if (valueSerializer != null && valueSerializer.CanConvertToString(_instance, Context)) { yield return new ElementStringValueProperty(this); if (_key != null) { yield return _key; } } else { Dictionary constructorArguments = null; // if this markup item is the value of property in attribute form and the instance // it represents is a MarkupExtension, then we return any properties that are // constructor arguments as ElementConstructorArgument markup properties if (mapToConstructorArgs && _instance is MarkupExtension) { // Detect if the instance should be constructed using constructor parameters by // seeing if it can be converted to an instance descriptor that uses a constructor. TypeConverter converter = TypeDescriptor.GetConverter(_instance); if (converter != null && converter.CanConvertTo(Context, typeof(InstanceDescriptor))) { InstanceDescriptor instanceDescriptor; try { instanceDescriptor = converter.ConvertTo(_context, System.Windows.Markup.TypeConverterHelper.EnglishUSCulture, _instance, typeof(InstanceDescriptor)) as InstanceDescriptor; } catch (InvalidOperationException) { // If we get this just ignore the converter instanceDescriptor = null; } catch (NotSupportedException) { // If we get this just ignore the converter instanceDescriptor = null; } if (instanceDescriptor != null) { ConstructorInfo ctorInfo = instanceDescriptor.MemberInfo as ConstructorInfo; if (ctorInfo != null) { ParameterInfo[] parameters = ctorInfo.GetParameters(); if (parameters != null && parameters.Length == instanceDescriptor.Arguments.Count) { int i = 0; foreach (object value in instanceDescriptor.Arguments) { if (constructorArguments == null) { constructorArguments = new Dictionary (); } // store a list of the parameters that are constructor arguments // so that we don't return those properties again constructorArguments.Add(parameters[i].Name, parameters[i].Name); yield return new ElementConstructorArgument(value, parameters[i++].ParameterType, this); } } } } } } foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(_instance)) { DesignerSerializationVisibility visibility = descriptor.SerializationVisibility; if (visibility != DesignerSerializationVisibility.Hidden && (!descriptor.IsReadOnly || visibility == DesignerSerializationVisibility.Content) && ShouldSerialize(descriptor, _instance, _manager)) { if (visibility == DesignerSerializationVisibility.Content) { // Ensure the collection has content object value = descriptor.GetValue(_instance); if (value == null) { continue; } else { ICollection collection = value as ICollection; if (collection != null && collection.Count < 1) { continue; } IEnumerable enumerable = value as IEnumerable; if (enumerable != null && !enumerable.GetEnumerator().MoveNext()) { continue; } } } if (constructorArguments != null) { ConstructorArgumentAttribute constructorArgumentAttribute = descriptor.Attributes[typeof(ConstructorArgumentAttribute)] as ConstructorArgumentAttribute; if (constructorArgumentAttribute != null && constructorArguments.ContainsKey(constructorArgumentAttribute.ArgumentName)) { // Skip this property, it has already been represented by a constructor parameter continue; } } yield return new ElementProperty(this, descriptor); } } IDictionary dictionary = _instance as IDictionary; if (dictionary != null) { yield return new ElementDictionaryItemsPseudoProperty(dictionary, typeof(IDictionary), this); } else { IEnumerable enumerable = _instance as IEnumerable; if (enumerable != null && enumerable.GetEnumerator().MoveNext()) { yield return new ElementItemsPseudoProperty(enumerable, typeof(IEnumerable), this); } } if (_key != null) { yield return _key; } } } public override AttributeCollection Attributes { get { return TypeDescriptor.GetAttributes(ObjectType); } } public override void AssignRootContext(IValueSerializerContext context) { _context = new ElementObjectContext(this, context); } internal IValueSerializerContext Context { get { return _context; } } internal XamlDesignerSerializationManager Manager { get { return _manager; } } internal void SetKey(ElementKey key) { _key = key; } private sealed class ElementObjectContext : ValueSerializerContextWrapper, IValueSerializerContext { ElementMarkupObject _object; public ElementObjectContext(ElementMarkupObject obj, IValueSerializerContext baseContext): base(baseContext) { _object = obj; } object ITypeDescriptorContext.Instance { get { return _object.Instance; } } } private static bool ShouldSerialize(PropertyDescriptor pd, object instance, XamlDesignerSerializationManager manager) { MethodInfo shouldSerializeMethod; object invokeInstance = instance; DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(pd); if (dpd != null && dpd.IsAttached) { Type ownerType = dpd.DependencyProperty.OwnerType; string propertyName = dpd.DependencyProperty.Name; string keyName = propertyName + "!"; if (!TryGetShouldSerializeMethod(new ShouldSerializeKey(ownerType, keyName), out shouldSerializeMethod)) { string methodName = "ShouldSerialize" + propertyName; shouldSerializeMethod = ownerType.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsObject, null); if (shouldSerializeMethod == null) shouldSerializeMethod = ownerType.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsManager, null); if (shouldSerializeMethod == null) shouldSerializeMethod = ownerType.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsMode, null); if (shouldSerializeMethod == null) shouldSerializeMethod = ownerType.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsObjectManager, null); if (shouldSerializeMethod != null && shouldSerializeMethod.ReturnType != typeof(bool)) shouldSerializeMethod = null; CacheShouldSerializeMethod(new ShouldSerializeKey(ownerType, keyName), shouldSerializeMethod); } invokeInstance = null; // static method } else { if (!TryGetShouldSerializeMethod(new ShouldSerializeKey(instance.GetType(), pd.Name), out shouldSerializeMethod)) { Type instanceType = instance.GetType(); string methodName = "ShouldSerialize" + pd.Name; shouldSerializeMethod = instanceType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsObject, null); if (shouldSerializeMethod == null) shouldSerializeMethod = instanceType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsManager, null); if (shouldSerializeMethod == null) shouldSerializeMethod = instanceType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsMode, null); if (shouldSerializeMethod == null) shouldSerializeMethod = instanceType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, _shouldSerializeArgsObjectManager, null); if (shouldSerializeMethod != null && shouldSerializeMethod.ReturnType != typeof(bool)) shouldSerializeMethod = null; CacheShouldSerializeMethod(new ShouldSerializeKey(instanceType, pd.Name), shouldSerializeMethod); } } if (shouldSerializeMethod != null) { ParameterInfo[] parameters = shouldSerializeMethod.GetParameters(); if (parameters != null) { object[] args; if (parameters.Length == 1) { if (parameters[0].ParameterType == typeof(DependencyObject)) { args = new object[] { instance as DependencyObject }; } else if (parameters[0].ParameterType == typeof(XamlWriterMode)) { args = new object[] { manager.XamlWriterMode }; } else { args = new object[] { manager }; } } else args = new object[] { instance as DependencyObject, manager }; return (bool)shouldSerializeMethod.Invoke(invokeInstance, args); } } return pd.ShouldSerializeValue(instance); } private struct ShouldSerializeKey { public ShouldSerializeKey(Type type, string propertyName) { _type = type; _propertyName = propertyName; } public override bool Equals(object obj) { if (!(obj is ShouldSerializeKey)) return false; ShouldSerializeKey other = (ShouldSerializeKey)obj; return other._type == _type && other._propertyName == _propertyName; } /// /// Forward to .Equals /// public static bool operator ==(ShouldSerializeKey key1, ShouldSerializeKey key2) { return key1.Equals(key2); } ////// Forward to .Equals /// public static bool operator !=(ShouldSerializeKey key1, ShouldSerializeKey key2) { return !(key1.Equals(key2)); } public override int GetHashCode() { return _type.GetHashCode() ^ _propertyName.GetHashCode(); } private Type _type; private string _propertyName; } private static bool TryGetShouldSerializeMethod(ShouldSerializeKey key, out MethodInfo methodInfo) { object value = _shouldSerializeCache[key]; if (value == null || value == _shouldSerializeCacheLock) { // The _shouldSerializeCacheLock is used as a sentinal for null methodInfo = null; return value != null; } else { methodInfo = value as MethodInfo; return true; } } private static void CacheShouldSerializeMethod(ShouldSerializeKey key, MethodInfo methodInfo) { // The instance stored in _shouldSerializeCacheLock is used as a sentinal for null // The avoids having to perform two lookups in the Hashtable to detect a cached null value. object value = methodInfo == null ? _shouldSerializeCacheLock : methodInfo; lock (_shouldSerializeCacheLock) { _shouldSerializeCache[key] = value; } } private static object _shouldSerializeCacheLock = new object(); private static Hashtable _shouldSerializeCache = new Hashtable(); private static Type[] _shouldSerializeArgsObject = new Type[] { typeof(DependencyObject) }; private static Type[] _shouldSerializeArgsManager = new Type[] { typeof(XamlDesignerSerializationManager) }; private static Type[] _shouldSerializeArgsMode = new Type[] { typeof(XamlWriterMode) }; private static Type[] _shouldSerializeArgsObjectManager = new Type[] { typeof(DependencyObject), typeof(XamlDesignerSerializationManager) }; private static Attribute[] _propertyAttributes = new Attribute[] { new PropertyFilterAttribute(PropertyFilterOptions.SetValues) }; private object _instance; private IValueSerializerContext _context; private ElementKey _key; private XamlDesignerSerializationManager _manager; } internal abstract class ElementPropertyBase : MarkupProperty { public ElementPropertyBase(XamlDesignerSerializationManager manager) { _manager = manager; } public override bool IsComposite { get { if (!_isCompositeCalculated) { _isCompositeCalculated = true; object value = Value; if (value == null) { _isComposite = true; } else if (value is string && PropertyType.IsAssignableFrom(typeof(object))) { _isComposite = false; } else if (value is MarkupExtension) { _isComposite = true; } else { _isComposite = !CanConvertToString(value); } } return _isComposite; } } public override string StringValue { get { if (IsComposite) { return String.Empty; } object value = Value; string stringValue = value as string; if (stringValue != null) { return stringValue; } ValueSerializer serializer = GetValueSerializer(); if (serializer == null) { return String.Empty; } return serializer.ConvertToString(value, Context); } } public override IEnumerableItems { get { object value = Value; if (value != null) { if (PropertyDescriptor != null && (PropertyDescriptor.IsReadOnly || (!PropertyIsAttached(PropertyDescriptor) && PropertyType == value.GetType() && // These types the serializer will synthesize a start element when // reading them in (typeof(IList).IsAssignableFrom(PropertyType) || typeof(IDictionary).IsAssignableFrom(PropertyType) || typeof(Freezable).IsAssignableFrom(PropertyType) || typeof(FrameworkElementFactory).IsAssignableFrom(PropertyType))) && HasNoSerializableProperties(value) && !IsEmpty(value))) { IDictionary dictionary = value as IDictionary; if (dictionary != null) { Type keyType = GetDictionaryKeyType(dictionary); // Attempt to emit the contents of the dictionary in a more deterministic // order. This is not guarenteed to be deterministic because it uses ToString // which is not guarenteed to be unique for each value. Keys with non-unique // ToString() values will not be emitted deterministically. DictionaryEntry[] entries = new DictionaryEntry[dictionary.Count]; dictionary.CopyTo(entries, 0); Array.Sort(entries, delegate(DictionaryEntry one, DictionaryEntry two) { return String.Compare(one.Key.ToString(), two.Key.ToString()); }); foreach (DictionaryEntry entry in entries) { ElementMarkupObject subItem = new ElementMarkupObject( ElementProperty.CheckForMarkupExtension(typeof(Object), entry.Value, Context, false), Manager); subItem.SetKey(new ElementKey(entry.Key, keyType, subItem)); yield return subItem; } } else { IEnumerable items = value as IEnumerable; if (items != null) { foreach (object o in items) { MarkupObject subItem = new ElementMarkupObject( ElementProperty.CheckForMarkupExtension(typeof(Object), o, Context, false), Manager); yield return subItem; } } else { if (PropertyType == typeof(FrameworkElementFactory) && value is FrameworkElementFactory) { MarkupObject subItem = new FrameworkElementFactoryMarkupObject(value as FrameworkElementFactory, Manager); yield return subItem; } else { MarkupObject subItem = new ElementMarkupObject( ElementProperty.CheckForMarkupExtension(typeof(Object), value, Context, true), Manager); yield return subItem; } } } } else { MarkupObject subItem = new ElementMarkupObject( ElementProperty.CheckForMarkupExtension(typeof(Object), value, Context, true), Manager); yield return subItem; } } else { MarkupObject subItem = new ElementMarkupObject(new System.Windows.Markup.NullExtension(), Manager); yield return subItem; } } } private bool PropertyIsAttached(PropertyDescriptor descriptor) { DependencyPropertyDescriptor dependencyPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(PropertyDescriptor); return dependencyPropertyDescriptor != null && dependencyPropertyDescriptor.IsAttached; } private bool HasNoSerializableProperties(object value) { if (value is FrameworkElementFactory) return true; ElementMarkupObject item = new ElementMarkupObject(value, Manager); foreach (MarkupProperty property in item.Properties) { if (!property.IsContent) { return false; } } return true; } private bool IsEmpty(object value) { IEnumerable collection = value as IEnumerable; if (collection != null) { foreach (object o in collection) return false; return true; } return false; } protected IValueSerializerContext Context { get { if (_context == null) { _context = new ElementPropertyContext(this, GetItemContext()); } return _context; } } internal XamlDesignerSerializationManager Manager { get { return _manager; } } static readonly List EmptyTypes = new List (); public override IEnumerable TypeReferences { get { ValueSerializer serializer = GetValueSerializer(); if (serializer == null) return EmptyTypes; else return serializer.TypeReferences(Value, Context); } } protected bool CanConvertToString( object value ) { // See if this value can be converted to a string by a value serializer or type converter if( value == null ) { return false; } ValueSerializer serializer = GetValueSerializer(); return serializer != null && serializer.CanConvertToString(value, Context); } protected abstract IValueSerializerContext GetItemContext(); protected abstract Type GetObjectType(); private sealed class ElementPropertyContext : ValueSerializerContextWrapper, IValueSerializerContext { ElementPropertyBase _property; public ElementPropertyContext(ElementPropertyBase property, IValueSerializerContext baseContext) : base(baseContext) { _property = property; } PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor { get { return _property.PropertyDescriptor; } } } private ValueSerializer GetValueSerializer() { PropertyDescriptor descriptor = this.PropertyDescriptor; if (descriptor == null) { DependencyProperty property = this.DependencyProperty; if (property != null) descriptor = DependencyPropertyDescriptor.FromProperty(property, GetObjectType()); } if (descriptor != null) return ValueSerializer.GetSerializerFor(descriptor, GetItemContext()); else return ValueSerializer.GetSerializerFor(PropertyType, GetItemContext()); } private static Dictionary _keyTypeMap; private static Type GetDictionaryKeyType(IDictionary value) { Type type = value.GetType(); Type result; if (_keyTypeMap == null) _keyTypeMap = new Dictionary (); if (!_keyTypeMap.TryGetValue(type, out result)) { foreach (Type interfaceType in type.GetInterfaces()) { if (interfaceType.IsGenericType) { Type genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(System.Collections.Generic.IDictionary<,>)) return interfaceType.GetGenericArguments()[0]; } } result = typeof(object); _keyTypeMap[type] = result; } return result; } private bool _isComposite; private bool _isCompositeCalculated; private IValueSerializerContext _context; private XamlDesignerSerializationManager _manager; } internal abstract class ElementObjectPropertyBase : ElementPropertyBase { protected ElementObjectPropertyBase(ElementMarkupObject obj): base(obj.Manager) { Debug.Assert(obj != null); _object = obj; } protected override IValueSerializerContext GetItemContext() { return _object.Context; } protected override Type GetObjectType() { return _object.ObjectType; } protected readonly ElementMarkupObject _object; } /// /// An implementation of MarkupProperty for DependencyObjects that works also for CLR only objects /// internal class ElementProperty : ElementObjectPropertyBase { internal ElementProperty(ElementMarkupObject obj, PropertyDescriptor descriptor) : base(obj) { Debug.Assert(descriptor != null); _descriptor = descriptor; } public override string Name { get { return _descriptor.Name; } } public override Type PropertyType { get { return _descriptor.PropertyType; } } public override PropertyDescriptor PropertyDescriptor { get { return _descriptor; } } public override bool IsAttached { get { UpdateDependencyProperty(); return _isAttached; } } public override DependencyProperty DependencyProperty { get { UpdateDependencyProperty(); return _dependencyProperty; } } public override object Value { get { object value; DependencyProperty DP = DependencyProperty; // For DPs, we use ReadLocalValue to find the property, and handle // unset values. if (DP != null) { DependencyObject DO = _object.Instance as DependencyObject; Debug.Assert(DO != null); // get the local value of the DP value = DO.ReadLocalValue(DP); // Expressions require special handling Expression expression = value as Expression; if (expression != null) { // Special-case: Expressions always get converted to an ME if // possible (and requested), and get de-referenced otherwise. TypeConverter converter = TypeDescriptor.GetConverter(value); if (Manager.XamlWriterMode == XamlWriterMode.Expression && converter.CanConvertTo(typeof(MarkupExtension))) { value = converter.ConvertTo(expression, typeof(MarkupExtension)); } else { value = expression.GetValue(DO, DP); } } // If the expression gave us UnsetValue, fall back to the default. if (value == DependencyProperty.UnsetValue) { value = DP.GetDefaultValue(DO.DependencyObjectType); } } // If this is the VisualTree property of a template, we have to do special processing. // Long-term plan is to replace this with an attribute on the type, that tells us how // to serialize its content. else if (Name == "VisualTree" && Context.Instance is FrameworkTemplate && (Context.Instance as FrameworkTemplate).HasContent ) { // Instantiate the template, in un-optimized form. This makes the template content // load as if it were loaded from xaml outside a template. The only exception is that // TemplateBinding's will show up as a TemplateBindingExtension. value = (Context.Instance as FrameworkTemplate).LoadContent(); } // Otherwise, get the value from the property descriptor. else { value = _descriptor.GetValue(_object.Instance); } // Convert the resulting value from above into a MarkupExtension, if necessary/possible, // but only if there is no value serializer; if the type supports conversion to both // string and ME, we give preference to the string conversion. if( !(value is MarkupExtension) && !CanConvertToString(value) ) { value = CheckForMarkupExtension(PropertyType, value, Context, true); } return value; } } public override AttributeCollection Attributes { get { return _descriptor.Attributes; } } private void UpdateDependencyProperty() { if (!_isDependencyPropertyCached) { DependencyPropertyDescriptor dpDesc = DependencyPropertyDescriptor.FromProperty(_descriptor); if (dpDesc != null) { _dependencyProperty = dpDesc.DependencyProperty; _isAttached = dpDesc.IsAttached; } _isDependencyPropertyCached = true; } } // // Check for values that can be converted into markup extensions, either because // they are a well known type ((null, arrays, enums, and types), or because they // can be type converted into an ME. // internal static object CheckForMarkupExtension( Type propertyType, object value, IValueSerializerContext context, bool convertEnums) { // null => NullExtension if (value == null) { return new NullExtension(); } // See if the type has a type converter that can create a MarkupExtension // (Have to do this after the null check so that GetConverter doesn't get // an invalid argument.) TypeConverter converter = TypeDescriptor.GetConverter(value); if (converter.CanConvertTo(context, typeof(MarkupExtension))) { // The type provides a converter that creates a MarkupExtension. return converter.ConvertTo(context, System.Windows.Markup.TypeConverterHelper.EnglishUSCulture, value, typeof(MarkupExtension)); } // System.Type => TypeExtension Type type = value as Type; if (type != null) { // If the property is declared to be a type already, we don't need to convert it // into {x:Type} syntax. if( propertyType == typeof(Type) ) { return value; } return new TypeExtension(type); } // Enums => StaticExtension if (convertEnums) { Enum enumValue = value as Enum; if (enumValue != null) { ValueSerializer typeSerializer = context.GetValueSerializerFor(typeof(Type)); Debug.Assert(typeSerializer != null, "typeSerializer for Enum was null"); string typeName = typeSerializer.ConvertToString(enumValue.GetType(), context); return new StaticExtension(typeName + "." + enumValue.ToString()); } } // Arrays => ArrayExtension Array array = value as Array; if (array != null) { return new ArrayExtension(array); } // Otherwise, value is unchanged. return value; } private PropertyDescriptor _descriptor; private bool _isDependencyPropertyCached; private DependencyProperty _dependencyProperty; private bool _isAttached; } ////// Pseudo-property for strings passed to a type converter /// internal class ElementStringValueProperty : MarkupProperty { internal ElementStringValueProperty(ElementMarkupObject obj) { _object = obj; } public override string Name { get { return "StringValue"; } } public override Type PropertyType { get { return typeof(string); } } public override bool IsValueAsString { get { return true; } } public override object Value { get { return StringValue; } } public override string StringValue { get { ValueSerializer serializer = ValueSerializer.GetSerializerFor(_object.ObjectType, _object.Context); Debug.Assert(serializer != null && serializer.CanConvertToString(_object.Instance, _object.Context), "StringValue property value created for a type that cannot be converted to string"); return serializer.ConvertToString(_object.Instance, _object.Context); } } public override IEnumerableItems { get { Debug.WriteLine("ElementMarkupObject.Items is not implemented"); return null; } } public override AttributeCollection Attributes { get { return AttributeCollection.Empty; } } public override IEnumerable TypeReferences { get { ValueSerializer serializer = ValueSerializer.GetSerializerFor(_object.ObjectType, _object.Context); Debug.Assert(serializer != null && serializer.CanConvertToString(_object.Instance, _object.Context), "StringValue property value created for a type that cannot be converted to string"); return serializer.TypeReferences(_object.Instance, _object.Context); } } private ElementMarkupObject _object; } /// /// Pseudo-property for the key of a dictionary element /// internal abstract class ElementPseudoPropertyBase : ElementObjectPropertyBase { internal ElementPseudoPropertyBase(object value, Type type, ElementMarkupObject obj) : base(obj) { _value = value; _type = type; } public override Type PropertyType { get { return _type; } } public override object Value { get { return ElementProperty.CheckForMarkupExtension(PropertyType, _value, Context, true /*convertEnums*/); } } public override AttributeCollection Attributes { get { return AttributeCollection.Empty; } } public override IEnumerableTypeReferences { get { return new Type[0]; } } private object _value; private Type _type; } /// /// Pseudo-property for the key of a dictionary element /// internal class ElementKey : ElementPseudoPropertyBase { internal ElementKey(object value, Type type, ElementMarkupObject obj) : base(value, type, obj) { } public override string Name { get { return "Key"; } } public override bool IsKey { get { return true; } } } ////// Pseudo-property for constructor arguments /// internal class ElementConstructorArgument : ElementPseudoPropertyBase { internal ElementConstructorArgument(object value, Type type, ElementMarkupObject obj) : base(value, type, obj) { } public override string Name { get { return "Argument"; } } public override bool IsConstructorArgument { get { return true; } } } ////// Pseudo-property for IEnumerable implementations /// internal class ElementItemsPseudoProperty : ElementPseudoPropertyBase { internal ElementItemsPseudoProperty(IEnumerable value, Type type, ElementMarkupObject obj) : base(value, type, obj) { _value = value; } public override string Name { get { return "Items"; } } public override bool IsContent { get { return true; } } public override bool IsComposite { get { return true; } } public override IEnumerableItems { get { foreach (object instance in _value) { yield return new ElementMarkupObject(instance, Manager); } } } IEnumerable _value; } /// /// Pseudo-property for IDictionary implementation /// internal class ElementDictionaryItemsPseudoProperty : ElementPseudoPropertyBase { internal ElementDictionaryItemsPseudoProperty(IDictionary value, Type type, ElementMarkupObject obj) : base(value, type, obj) { _value = value; } public override string Name { get { return "Entries"; } } public override bool IsContent { get { return true; } } public override bool IsComposite { get { return true; } } public override IEnumerableItems { get { foreach (DictionaryEntry entry in _value) { ElementMarkupObject item = new ElementMarkupObject(entry.Value, Manager); item.SetKey(new ElementKey(entry.Key, typeof(object), item)); yield return item; } } } IDictionary _value; } internal class ValueSerializerContextWrapper : IValueSerializerContext { IValueSerializerContext _baseContext; public ValueSerializerContextWrapper(IValueSerializerContext baseContext) { _baseContext = baseContext; } public ValueSerializer GetValueSerializerFor(PropertyDescriptor descriptor) { if (_baseContext != null) return _baseContext.GetValueSerializerFor(descriptor); else return null; } public ValueSerializer GetValueSerializerFor(Type type) { if (_baseContext != null) return _baseContext.GetValueSerializerFor(type); else return null; } public IContainer Container { get { if (_baseContext != null) return _baseContext.Container; else return null; } } public object Instance { get { if (_baseContext != null) return _baseContext.Instance; else return null; } } public void OnComponentChanged() { if (_baseContext != null) _baseContext.OnComponentChanged(); } public bool OnComponentChanging() { if (_baseContext != null) return _baseContext.OnComponentChanging(); else return true; } public PropertyDescriptor PropertyDescriptor { get { if (_baseContext != null) return _baseContext.PropertyDescriptor; else return null; } } public object GetService(Type serviceType) { if (_baseContext != null) return _baseContext.GetService(serviceType); else return null; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- FunctionDetailsReader.cs
- SpeakProgressEventArgs.cs
- PrincipalPermission.cs
- SQLRoleProvider.cs
- AutomationTextAttribute.cs
- LinqDataSourceValidationException.cs
- SchemaNames.cs
- SapiAttributeParser.cs
- UpdatePanelControlTrigger.cs
- SafeCryptHandles.cs
- OracleConnectionString.cs
- MenuAutomationPeer.cs
- XPathAncestorQuery.cs
- HttpRuntime.cs
- ToolStripScrollButton.cs
- QuestionEventArgs.cs
- HostingEnvironment.cs
- HTTPNotFoundHandler.cs
- EntityDataSourceView.cs
- DependencyPropertyAttribute.cs
- InkPresenter.cs
- PeerNameRecordCollection.cs
- OneOfConst.cs
- StandardOleMarshalObject.cs
- DBCommand.cs
- GenericTypeParameterConverter.cs
- PointValueSerializer.cs
- RuleElement.cs
- SafeNativeMethods.cs
- TdsParserStateObject.cs
- MemoryRecordBuffer.cs
- XmlCountingReader.cs
- ToolBarButton.cs
- ProvidersHelper.cs
- ImageList.cs
- IsolatedStorageSecurityState.cs
- ArithmeticException.cs
- ProviderUtil.cs
- DocumentOrderComparer.cs
- JsonByteArrayDataContract.cs
- UserPersonalizationStateInfo.cs
- HttpInputStream.cs
- ClusterRegistryConfigurationProvider.cs
- ClientConvert.cs
- Int32RectConverter.cs
- PartitionResolver.cs
- CommandID.cs
- FunctionImportElement.cs
- COM2ICategorizePropertiesHandler.cs
- StringFreezingAttribute.cs
- SettingsPropertyValue.cs
- FrameworkContentElementAutomationPeer.cs
- RegexFCD.cs
- RemotingServices.cs
- UnhandledExceptionEventArgs.cs
- WebPartRestoreVerb.cs
- NegationPusher.cs
- AdCreatedEventArgs.cs
- DbParameterHelper.cs
- ConstructorArgumentAttribute.cs
- COM2Enum.cs
- StringHandle.cs
- Transform.cs
- TextChangedEventArgs.cs
- OdbcPermission.cs
- IteratorFilter.cs
- IndexerNameAttribute.cs
- AccessDataSource.cs
- MetadataPropertyCollection.cs
- CompModSwitches.cs
- SiteMapDataSourceView.cs
- SqlRetyper.cs
- DataBindingHandlerAttribute.cs
- EntityDataSourceQueryBuilder.cs
- KeyConverter.cs
- EdgeProfileValidation.cs
- CheckBoxDesigner.cs
- FileDialog_Vista.cs
- XmlSchemaAnnotated.cs
- DataGridColumnsPage.cs
- TableItemPatternIdentifiers.cs
- TableLayoutColumnStyleCollection.cs
- DesignTimeTemplateParser.cs
- InfocardClientCredentials.cs
- MatchAttribute.cs
- TypeNameHelper.cs
- DockPatternIdentifiers.cs
- TextInfo.cs
- GenericUriParser.cs
- SafeCryptoHandles.cs
- ScaleTransform3D.cs
- x509utils.cs
- CharUnicodeInfo.cs
- RelationshipConverter.cs
- UnitySerializationHolder.cs
- Compress.cs
- TypeName.cs
- TemplateXamlParser.cs
- BamlLocalizableResourceKey.cs
- XmlBindingWorker.cs