ElementMarkupObject.cs source code in C# .NET

Source code for the .NET framework in C#

                        

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 IEnumerable GetProperties(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 IEnumerable Items
        { 
            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 IEnumerable Items 
        {
            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 IEnumerable TypeReferences 
        {
            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 IEnumerable Items
        { 
            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 IEnumerable Items
        { 
            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 IEnumerable GetProperties(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 IEnumerable Items
        { 
            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 IEnumerable Items 
        {
            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 IEnumerable TypeReferences 
        {
            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 IEnumerable Items
        { 
            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 IEnumerable Items
        { 
            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

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK