ModelItemDictionaryImpl.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / Tools / System.Activities.Presentation / System / Activities / Presentation / Model / ModelItemDictionaryImpl.cs / 1305376 / ModelItemDictionaryImpl.cs

                            //---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------
namespace System.Activities.Presentation.Model
{ 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Collections.Specialized; 
    using System.ComponentModel;
    using System.Diagnostics; 
    using System.Windows;
    using System.Windows.Markup;
    using System.Activities.Presentation.Services;
    using System.Linq; 
    using System.Reflection;
    using System.Runtime; 
    using System.Diagnostics.CodeAnalysis; 
    using System.Globalization;
 
    class ModelItemDictionaryImpl : ModelItemDictionary, IModelTreeItem, ICustomTypeDescriptor
    {
        ModelProperty contentProperty;
        DictionaryWrapper instance; 
        Type itemType;
        Dictionary modelItems; 
        Dictionary modelPropertyStore; 
        ModelTreeManager modelTreeManager;
        ModelProperty nameProperty; 
        List parents;
        ModelPropertyCollectionImpl properties;
        List sources;
        List subTreeNodesThatNeedBackLinkPatching; 
        DependencyObject view;
 
        public ModelItemDictionaryImpl(ModelTreeManager modelTreeManager, Type itemType, Object instance, ModelItem parent) 
        {
            Fx.Assert(modelTreeManager != null, "modelTreeManager cannot be null"); 
            Fx.Assert(itemType != null, "item type cannot be null");
            Fx.Assert(instance != null, "instance cannot be null");
            this.itemType = itemType;
            this.instance = new DictionaryWrapper(instance); 
            this.modelTreeManager = modelTreeManager;
            this.parents = new List(1); 
            this.sources = new List(1); 
            if (parent != null)
            { 
                this.parents.Add(parent);
            }
            this.modelPropertyStore = new Dictionary();
            this.subTreeNodesThatNeedBackLinkPatching = new List(); 
            this.modelItems = new Dictionary();
            UpdateInstance(); 
        } 

        public override event NotifyCollectionChangedEventHandler CollectionChanged; 

        public override event PropertyChangedEventHandler PropertyChanged;

        public override int Count 
        {
            get { return this.instance.Count; } 
        } 

        public override bool IsReadOnly 
        {
            get { return this.instance.IsReadOnly; }
        }
 
        public override ICollection Keys
        { 
            get { return this.modelItems.Keys; } 
        }
 
        public override ICollection Values
        {
            get { return this.modelItems.Values; }
        } 

        public override AttributeCollection Attributes 
        { 
            get
            { 
                Fx.Assert(null != this.itemType, "ItemType cannot be null!");
                return TypeDescriptor.GetAttributes(this.itemType);
            }
        } 

        public override ModelProperty Content 
        { 
            get
            { 
                if (this.contentProperty == null)
                {
                    Fx.Assert(this.instance != null, "instance cannot be null");
                    ContentPropertyAttribute contentAttribute = TypeDescriptor.GetAttributes(this.instance.Value)[typeof(ContentPropertyAttribute)] as ContentPropertyAttribute; 
                    if (contentAttribute != null && !String.IsNullOrEmpty(contentAttribute.Name))
                    { 
                        this.contentProperty = this.Properties.Find(contentAttribute.Name); 
                    }
                } 
                return contentProperty;
            }
        }
 
        public override Type ItemType
        { 
            get { return this.itemType; } 
        }
 
        public override string Name
        {
            get
            { 
                string name = null;
                if ((this.NameProperty != null) && (this.NameProperty.Value != null)) 
                { 
                    name = (string)this.NameProperty.Value.GetCurrentValue();
                } 
                return name;
            }
            set
            { 
                if (null != this.NameProperty)
                { 
                    this.NameProperty.SetValue(value); 
                }
            } 
        }

        public override ModelItem Parent
        { 
            get
            { 
                return (this.Parents.Count() > 0) ? this.Parents.First() : null; 
            }
 
        }

        public override ModelItem Root
        { 
            get { return this.modelTreeManager.Root; }
        } 
 
        public override ModelPropertyCollection Properties
        { 
            get
            {
                if (this.properties == null)
                { 
                    this.properties = new ModelPropertyCollectionImpl(this);
                } 
                return this.properties; 
            }
        } 

        public override ModelProperty Source
        {
            get 
            {
                return (this.sources.Count > 0) ? this.sources.First() : null; 
            } 
        }
 
        public override DependencyObject View
        {
            get { return this.view; }
        } 

        public ModelItem ModelItem 
        { 
            get { return this; }
        } 

        public Dictionary ModelPropertyStore
        {
            get { return this.modelPropertyStore; } 
        }
 
        public ModelTreeManager ModelTreeManager 
        {
            get { return this.modelTreeManager; } 
        }


        public override IEnumerable Parents 
        {
            get 
            { 
                return this.parents.Concat(
                    from source in this.sources 
                    select source.Parent);
            }
        }
 
        public override IEnumerable Sources
        { 
            get 
            {
                return this.sources; 
            }
        }

        protected ModelProperty NameProperty 
        {
            get 
            { 
                if (this.nameProperty == null)
                { 
                    Fx.Assert(this.instance != null, "instance cannot be null");
                    RuntimeNamePropertyAttribute runtimeNamePropertyAttribute = TypeDescriptor.GetAttributes(this.instance.Value)[typeof(RuntimeNamePropertyAttribute)] as RuntimeNamePropertyAttribute;
                    if (runtimeNamePropertyAttribute != null && !String.IsNullOrEmpty(runtimeNamePropertyAttribute.Name))
                    { 
                        this.nameProperty = this.Properties.Find(runtimeNamePropertyAttribute.Name);
                    } 
                    else 
                    {
                        this.nameProperty = this.Properties.FirstOrDefault(p => (0 == string.Compare(p.Name, "Name", StringComparison.OrdinalIgnoreCase))); 
                    }
                }
                return nameProperty;
            } 
        }
 
        public override ModelItem this[ModelItem key] 
        {
            get 
            {
                if (null == key || null == key.GetCurrentValue())
                {
                    throw FxTrace.Exception.AsError( new ArgumentNullException("key")); 
                }
                ModelItem value; 
                if (!this.modelItems.TryGetValue(key, out value)) 
                {
                    throw FxTrace.Exception.AsError( new KeyNotFoundException(key.GetCurrentValue().ToString())); 
                }
                return value;
            }
            set 
            {
                if (null == key || null == key.GetCurrentValue()) 
                { 
                    throw FxTrace.Exception.AsError( new ArgumentNullException("key"));
                } 
                if (this.instance.IsReadOnly)
                {
                    throw FxTrace.Exception.AsError( new InvalidOperationException(SR.CollectionIsReadOnly));
                } 
                ModelItem oldValue = null;
                if (this.modelItems.TryGetValue(key, out oldValue)) 
                { 
                    this.modelTreeManager.DictionaryEdit(this, key, value, oldValue);
                } 
                else
                {
                    this.modelTreeManager.DictionaryAdd(this, key, value);
                } 
            }
        } 
 
        public override ModelItem this[object key]
        { 
            get
            {
                if (null == key)
                { 
                    throw FxTrace.Exception.AsError( new ArgumentNullException("key"));
                } 
 
                ModelItem keyItem = this.KeyAsModelItem(key, false);
 
                if (null == keyItem)
                {
                    throw FxTrace.Exception.AsError( new KeyNotFoundException(key.ToString()));
                } 
                return this[keyItem];
            } 
            set 
            {
                if (null == key) 
                {
                    throw FxTrace.Exception.AsError( new ArgumentNullException("key"));
                }
 
                if (this.instance.IsReadOnly)
                { 
                    throw FxTrace.Exception.AsError( new InvalidOperationException(SR.CollectionIsReadOnly)); 
                }
 
                ModelItem keyItem = this.KeyAsModelItem(key, true);

                this[keyItem] = value;
            } 
        }
 
        public override void Add(ModelItem key, ModelItem value) 
        {
            if (null == key) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("key"));
            }
            if (this.instance.IsReadOnly) 
            {
                throw FxTrace.Exception.AsError( new InvalidOperationException(SR.CollectionIsReadOnly)); 
            } 
            this.modelTreeManager.DictionaryAdd(this, key, value);
        } 

        public override ModelItem Add(object key, object value)
        {
            if (null == key) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("key")); 
            } 
            if (this.instance.IsReadOnly)
            { 
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CollectionIsReadOnly));
            }
            ModelItem keyModelItem = key as ModelItem ?? this.WrapObject(key);
            ModelItem valueModelItem = value as ModelItem ?? this.WrapObject(value); 
            this.Add(keyModelItem, valueModelItem);
            return valueModelItem; 
        } 

        public override void Clear() 
        {
            this.modelTreeManager.DictionaryClear(this);
        }
 
        public override bool ContainsKey(ModelItem key)
        { 
            if (null == key) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("key")); 
            }
            return this.modelItems.Keys.Contains(key);
        }
 
        public override bool ContainsKey(object key)
        { 
            if (null == key) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("key")); 
            }
            if (typeof(ModelItem).IsAssignableFrom(key.GetType()))
            {
                return this.ContainsKey(key as ModelItem); 
            }
            return null != this.modelItems.Keys.SingleOrDefault(p => object.Equals(p.GetCurrentValue(), key)); 
        } 

        public override IEnumerator> GetEnumerator() 
        {
            return this.modelItems.GetEnumerator();
        }
 
        public override bool Remove(ModelItem key)
        { 
            if (null == key) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("key")); 
            }
            this.modelTreeManager.DictionaryRemove(this, key);
            return true;
        } 

        public override bool Remove(object key) 
        { 
            if (null == key)
            { 
                throw FxTrace.Exception.AsError( new ArgumentNullException("key"));
            }
            ModelItem keyItem = this.KeyAsModelItem(key, false);
 
            if (null != keyItem)
            { 
                return this.Remove(keyItem); 
            }
            return false; 
        }

        public override bool TryGetValue(ModelItem key, out ModelItem value)
        { 
            if (null == key)
            { 
                throw FxTrace.Exception.AsError( new ArgumentNullException("key")); 
            }
            return this.modelItems.TryGetValue(key, out value); 
        }

        public override bool TryGetValue(object key, out ModelItem value)
        { 
            if (null == key)
            { 
                throw FxTrace.Exception.AsError( new ArgumentNullException("key")); 
            }
            ModelItem keyItem = this.KeyAsModelItem(key, false); 
            if (null == keyItem)
            {
                value = null;
                return false; 
            }
            return this.TryGetValue(keyItem, out value); 
        } 

        public override ModelEditingScope BeginEdit(string description) 
        {
            return this.modelTreeManager.CreateEditingScope(description);
        }
 
        public override ModelEditingScope BeginEdit()
        { 
            return this.BeginEdit(null); 
        }
 
        public override object GetCurrentValue()
        {
            return this.instance.Value;
        } 

        #region IModelTreeItem Members 
 

        public void OnPropertyChanged(string propertyName) 
        {
            if (null != this.PropertyChanged)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
            }
        } 
 
        void IModelTreeItem.SetParent(ModelItem dataModelItem)
        { 
            if (!this.parents.Contains(dataModelItem))
            {
                this.parents.Add(dataModelItem);
            } 
        }
 
        void IModelTreeItem.SetSource(ModelProperty property) 
        {
            if (!this.sources.Contains(property)) 
            {
                // also check if the same parent.property is in the list as a different instance of oldModelProperty
                ModelProperty foundProperty = this.sources.Find((modelProperty) => modelProperty.Name.Equals(property.Name) && property.Parent == modelProperty.Parent);
                if (foundProperty == null) 
                {
                    this.sources.Add(property); 
                } 
            }
        } 

        IList IModelTreeItem.SubNodesThatNeedBackLinkUpdate
        {
            get 
            {
                return this.subTreeNodesThatNeedBackLinkPatching; 
            } 
        }
 
        public void SetCurrentView(DependencyObject view)
        {
            this.view = view;
        } 

        #endregion 
 
        void IModelTreeItem.RemoveParent(ModelItem oldParent)
        { 
            if (this.parents.Contains(oldParent))
            {
                this.parents.Remove(oldParent);
            } 
        }
 
        void IModelTreeItem.RemoveSource(ModelProperty oldModelProperty) 
        {
            if (this.sources.Contains(oldModelProperty)) 
            {
                this.sources.Remove(oldModelProperty);
            }
            else 
            {
                // also check if the same parent.property is in the list as a different instance of oldModelProperty 
                ModelProperty foundProperty = this.sources.Find((modelProperty) => modelProperty.Name.Equals(oldModelProperty.Name) && modelProperty.Parent == oldModelProperty.Parent); 
                if (foundProperty != null)
                { 
                    this.sources.Remove(foundProperty);
                }
                else
                { 
                    Fx.Assert("Trying to call RemoveSource() on modelItem that is not parented by oldModelProperty");
                } 
            } 
        }
 


        internal void EditCore(ModelItem key, ModelItem value)
        { 
            Fx.Assert(this.instance != null, "instance should not be null");
            if (key.Parent != this) 
            { 
                ((IModelTreeItem)key).SetParent(this);
            } 
            if (null != value && value.Parent != this)
            {
                ((IModelTreeItem)value).SetParent(this);
            } 
            this.instance[key.GetCurrentValue()] = null != value ? value.GetCurrentValue() : null;
            ModelItem oldValue = this.modelItems[key]; 
            this.modelItems[key] = value; 
            if (null != this.CollectionChanged)
            { 
                this.CollectionChanged(this,
                    new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace,
                    new KeyValuePair(key, value),
                    new KeyValuePair(key, oldValue))); 
            }
        } 
 
        internal void AddCore(ModelItem key, ModelItem value)
        { 
            Fx.Assert(this.instance != null, "instance should not be null");
            if (key.Parent != this)
            {
                ((IModelTreeItem)key).SetParent(this); 
            }
            if (null != value && value.Parent != this) 
            { 
                ((IModelTreeItem)value).SetParent(this);
            } 
            this.instance.Add(key.GetCurrentValue(), null != value ? value.GetCurrentValue() : null);
            this.modelItems.Add(key, value);
            if (null != this.CollectionChanged)
            { 
                this.CollectionChanged(this,
                    new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, 
                    new KeyValuePair(key, value))); 
            }
        } 

        internal void ClearCore()
        {
            Fx.Assert(this.instance != null, "instance should not be null"); 
            IList removed = this.modelItems.ToList>();
            this.instance.Clear(); 
            this.modelItems.Clear(); 
            if (null != this.CollectionChanged)
            { 
                this.CollectionChanged(this,
                    new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed));
            }
        } 

        internal void RemoveCore(ModelItem key) 
        { 
            Fx.Assert(this.instance != null, "instance should not be null");
            ModelItem value = this.modelItems[key]; 
            this.modelItems.Remove(key);
            this.instance.Remove(key.GetCurrentValue());
            if (null != this.CollectionChanged)
            { 
                this.CollectionChanged(this,
                    new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new KeyValuePair(key, value))); 
            } 
        }
 
        void UpdateInstance()
        {
            IEnumerator dictionaryEnumerator = this.instance.GetEnumerator();
            while (dictionaryEnumerator.MoveNext()) 
            {
                object current = dictionaryEnumerator.Current; 
 
                ModelItem key = this.WrapObject(instance.GetKeyFromCurrent(current));
                ModelItem value = this.WrapObject(instance.GetValueFromCurrent(current)); 
                if (key != null)
                {
                    this.modelItems.Add(key, value);
                } 
            }
        } 
 
        ModelItem WrapObject(object value)
        { 
            return this.ModelTreeManager.WrapAsModelItem(this, value);
        }

        ModelItem KeyAsModelItem(object value, bool createNew) 
        {
            ModelItem result = (value as ModelItem) ?? (ModelItem)this.modelItems.Keys.SingleOrDefault 
                (p => object.Equals(p.GetCurrentValue(), value)); 
            if (createNew && null == result)
            { 
                result = WrapObject(value);
            }
            return result;
        } 

        sealed class DictionaryWrapper 
        { 
            object instance;
            bool isDictionary = false; 
            PropertyInfo isReadOnlyProperty;
            PropertyInfo countProperty;
            PropertyInfo indexingProperty;
            MethodInfo addMethod; 
            MethodInfo removeMethod;
            MethodInfo clearMethod; 
            MethodInfo getEnumeratorMethod; 
            PropertyInfo keyProperty;
            PropertyInfo valueProperty; 

            public DictionaryWrapper(object instance)
            {
                this.instance = instance; 
                if (instance is IDictionary)
                { 
                    this.isDictionary = true; 
                    Type keyValuePairType = typeof(KeyValuePair);
                } 
                else
                {
                    Type instanceType = instance.GetType();
                    instanceType.FindInterfaces(this.GetDictionaryInterface, null); 
                }
            } 
 
            public object Value
            { 
                get { return this.instance; }
            }

            public bool IsReadOnly 
            {
                get 
                { 
                    return (this.isDictionary ? ((IDictionary)instance).IsReadOnly : (bool)this.isReadOnlyProperty.GetValue(this.instance, null));
                } 
            }

            public int Count
            { 
                get
                { 
                    return (this.isDictionary ? ((IDictionary)instance).Count : (int)this.countProperty.GetValue(this.instance, null)); 
                }
            } 

            [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification="This is intended for use through reflection")]
            public object this[object key]
            { 
                get
                { 
                    if (this.isDictionary) 
                    {
                        return ((IDictionary)instance)[key]; 
                    }
                    else
                    {
                        return this.indexingProperty.GetValue(this.instance, new object[] { key }); 
                    }
                } 
                set 
                {
                    if (this.isDictionary) 
                    {
                        ((IDictionary)instance)[key] = value;
                    }
                    else 
                    {
                        this.indexingProperty.SetValue(this.instance, value, new object[] { key }); 
                    } 
                }
            } 

            public object GetKeyFromCurrent(object keyValuePair)
            {
                if (isDictionary) 
                {
                    return ((DictionaryEntry)keyValuePair).Key; 
                } 
                else
                { 
                    return this.keyProperty.GetValue(keyValuePair, null);
                }
            }
 
            public object GetValueFromCurrent(object keyValuePair)
            { 
                if (isDictionary) 
                {
                    return ((DictionaryEntry)keyValuePair).Value; 
                }
                else
                {
                    return this.valueProperty.GetValue(keyValuePair, null); 
                }
            } 
 

            bool GetDictionaryInterface(Type type, object dummy) 
            {
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
                {
                    this.addMethod = type.GetMethod("Add"); 
                    this.removeMethod = type.GetMethod("Remove");
                    this.indexingProperty = type.GetProperty("Item"); 
                    return true; 
                }
                if (type.IsGenericType && 
                    type.GetGenericArguments()[0].IsGenericType &&
                    type.GetGenericArguments()[0].GetGenericTypeDefinition() == typeof(KeyValuePair<,>) &&
                    type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
                { 
                    Type keyValuePairType = type.GetGenericArguments()[0];
                    this.keyProperty = keyValuePairType.GetProperty("Key"); 
                    this.valueProperty = keyValuePairType.GetProperty("Value"); 
                    this.getEnumeratorMethod = type.GetMethod("GetEnumerator");
                    return true; 
                }
                if (type.IsGenericType &&
                    type.GetGenericArguments()[0].IsGenericType &&
                    type.GetGenericArguments()[0].GetGenericTypeDefinition() == typeof(KeyValuePair<,>) && 
                    type.GetGenericTypeDefinition() == typeof(ICollection<>))
                { 
                    this.isReadOnlyProperty = type.GetProperty("IsReadOnly"); 
                    this.countProperty = type.GetProperty("Count");
                    this.clearMethod = type.GetMethod("Clear"); 
                }
                return false;
            }
 

            public void Add(object key, object value) 
            { 
                if (this.isDictionary)
                { 
                    ((IDictionary)instance).Add(key, value);
                }
                else
                { 
                    this.addMethod.Invoke(this.instance, new object[] { key, value });
                } 
            } 

            public void Clear() 
            {
                if (this.isDictionary)
                {
                    ((IDictionary)instance).Clear(); 
                }
                else 
                { 
                    this.clearMethod.Invoke(this.instance, null);
                } 
            }

            public IEnumerator GetEnumerator()
            { 
                if (this.isDictionary)
                { 
                    return ((IDictionary)instance).GetEnumerator(); 
                }
                else 
                {
                    return (IEnumerator)this.getEnumeratorMethod.Invoke(this.instance, null);
                }
            } 

            public void Remove(object key) 
            { 
                if (this.isDictionary)
                { 
                    ((IDictionary)instance).Remove(key);
                }
                else
                { 
                    this.removeMethod.Invoke(this.instance, new object[] { key });
                } 
            } 

 
        }

        AttributeCollection ICustomTypeDescriptor.GetAttributes()
        { 
            return this.Attributes;
        } 
 
        string ICustomTypeDescriptor.GetClassName()
        { 
            return TypeDescriptor.GetClassName(this);
        }

        string ICustomTypeDescriptor.GetComponentName() 
        {
            return TypeDescriptor.GetComponentName(this); 
        } 

        TypeConverter ICustomTypeDescriptor.GetConverter() 
        {
            return ModelUtilities.GetConverter(this);
        }
 
        EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
        { 
            // we dont support events; 
            return null;
        } 

        PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
        {
            return ModelUtilities.GetDefaultProperty(this); 
        }
 
        object ICustomTypeDescriptor.GetEditor(Type editorBaseType) 
        {
            // we dont support editors 
            return null;
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) 
        {
            // we dont support events; 
            return null; 
        }
 
        EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
        {
            // we dont support events;
            return null; 
        }
 
        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) 
        {
            return ModelUtilities.WrapProperties(this); 
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
        { 
            // get model properties
            List properties = new List(); 
 

            foreach (PropertyDescriptor modelPropertyDescriptor in ModelUtilities.WrapProperties(this)) 
            {
                properties.Add(modelPropertyDescriptor);
            }
 
            // try to see if there are pseudo builtin properties for this type.
            AttachedPropertiesService AttachedPropertiesService = this.modelTreeManager.Context.Services.GetService(); 
            if (AttachedPropertiesService != null) 
            {
                foreach (AttachedProperty AttachedProperty in AttachedPropertiesService.GetAttachedProperties(this.itemType)) 
                {
                    properties.Add(new AttachedPropertyDescriptor(AttachedProperty, this));
                }
            } 
            return new PropertyDescriptorCollection(properties.ToArray(), true);
        } 
 
        object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
        { 
            return this;
        }

    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------
namespace System.Activities.Presentation.Model
{ 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Collections.Specialized; 
    using System.ComponentModel;
    using System.Diagnostics; 
    using System.Windows;
    using System.Windows.Markup;
    using System.Activities.Presentation.Services;
    using System.Linq; 
    using System.Reflection;
    using System.Runtime; 
    using System.Diagnostics.CodeAnalysis; 
    using System.Globalization;
 
    class ModelItemDictionaryImpl : ModelItemDictionary, IModelTreeItem, ICustomTypeDescriptor
    {
        ModelProperty contentProperty;
        DictionaryWrapper instance; 
        Type itemType;
        Dictionary modelItems; 
        Dictionary modelPropertyStore; 
        ModelTreeManager modelTreeManager;
        ModelProperty nameProperty; 
        List parents;
        ModelPropertyCollectionImpl properties;
        List sources;
        List subTreeNodesThatNeedBackLinkPatching; 
        DependencyObject view;
 
        public ModelItemDictionaryImpl(ModelTreeManager modelTreeManager, Type itemType, Object instance, ModelItem parent) 
        {
            Fx.Assert(modelTreeManager != null, "modelTreeManager cannot be null"); 
            Fx.Assert(itemType != null, "item type cannot be null");
            Fx.Assert(instance != null, "instance cannot be null");
            this.itemType = itemType;
            this.instance = new DictionaryWrapper(instance); 
            this.modelTreeManager = modelTreeManager;
            this.parents = new List(1); 
            this.sources = new List(1); 
            if (parent != null)
            { 
                this.parents.Add(parent);
            }
            this.modelPropertyStore = new Dictionary();
            this.subTreeNodesThatNeedBackLinkPatching = new List(); 
            this.modelItems = new Dictionary();
            UpdateInstance(); 
        } 

        public override event NotifyCollectionChangedEventHandler CollectionChanged; 

        public override event PropertyChangedEventHandler PropertyChanged;

        public override int Count 
        {
            get { return this.instance.Count; } 
        } 

        public override bool IsReadOnly 
        {
            get { return this.instance.IsReadOnly; }
        }
 
        public override ICollection Keys
        { 
            get { return this.modelItems.Keys; } 
        }
 
        public override ICollection Values
        {
            get { return this.modelItems.Values; }
        } 

        public override AttributeCollection Attributes 
        { 
            get
            { 
                Fx.Assert(null != this.itemType, "ItemType cannot be null!");
                return TypeDescriptor.GetAttributes(this.itemType);
            }
        } 

        public override ModelProperty Content 
        { 
            get
            { 
                if (this.contentProperty == null)
                {
                    Fx.Assert(this.instance != null, "instance cannot be null");
                    ContentPropertyAttribute contentAttribute = TypeDescriptor.GetAttributes(this.instance.Value)[typeof(ContentPropertyAttribute)] as ContentPropertyAttribute; 
                    if (contentAttribute != null && !String.IsNullOrEmpty(contentAttribute.Name))
                    { 
                        this.contentProperty = this.Properties.Find(contentAttribute.Name); 
                    }
                } 
                return contentProperty;
            }
        }
 
        public override Type ItemType
        { 
            get { return this.itemType; } 
        }
 
        public override string Name
        {
            get
            { 
                string name = null;
                if ((this.NameProperty != null) && (this.NameProperty.Value != null)) 
                { 
                    name = (string)this.NameProperty.Value.GetCurrentValue();
                } 
                return name;
            }
            set
            { 
                if (null != this.NameProperty)
                { 
                    this.NameProperty.SetValue(value); 
                }
            } 
        }

        public override ModelItem Parent
        { 
            get
            { 
                return (this.Parents.Count() > 0) ? this.Parents.First() : null; 
            }
 
        }

        public override ModelItem Root
        { 
            get { return this.modelTreeManager.Root; }
        } 
 
        public override ModelPropertyCollection Properties
        { 
            get
            {
                if (this.properties == null)
                { 
                    this.properties = new ModelPropertyCollectionImpl(this);
                } 
                return this.properties; 
            }
        } 

        public override ModelProperty Source
        {
            get 
            {
                return (this.sources.Count > 0) ? this.sources.First() : null; 
            } 
        }
 
        public override DependencyObject View
        {
            get { return this.view; }
        } 

        public ModelItem ModelItem 
        { 
            get { return this; }
        } 

        public Dictionary ModelPropertyStore
        {
            get { return this.modelPropertyStore; } 
        }
 
        public ModelTreeManager ModelTreeManager 
        {
            get { return this.modelTreeManager; } 
        }


        public override IEnumerable Parents 
        {
            get 
            { 
                return this.parents.Concat(
                    from source in this.sources 
                    select source.Parent);
            }
        }
 
        public override IEnumerable Sources
        { 
            get 
            {
                return this.sources; 
            }
        }

        protected ModelProperty NameProperty 
        {
            get 
            { 
                if (this.nameProperty == null)
                { 
                    Fx.Assert(this.instance != null, "instance cannot be null");
                    RuntimeNamePropertyAttribute runtimeNamePropertyAttribute = TypeDescriptor.GetAttributes(this.instance.Value)[typeof(RuntimeNamePropertyAttribute)] as RuntimeNamePropertyAttribute;
                    if (runtimeNamePropertyAttribute != null && !String.IsNullOrEmpty(runtimeNamePropertyAttribute.Name))
                    { 
                        this.nameProperty = this.Properties.Find(runtimeNamePropertyAttribute.Name);
                    } 
                    else 
                    {
                        this.nameProperty = this.Properties.FirstOrDefault(p => (0 == string.Compare(p.Name, "Name", StringComparison.OrdinalIgnoreCase))); 
                    }
                }
                return nameProperty;
            } 
        }
 
        public override ModelItem this[ModelItem key] 
        {
            get 
            {
                if (null == key || null == key.GetCurrentValue())
                {
                    throw FxTrace.Exception.AsError( new ArgumentNullException("key")); 
                }
                ModelItem value; 
                if (!this.modelItems.TryGetValue(key, out value)) 
                {
                    throw FxTrace.Exception.AsError( new KeyNotFoundException(key.GetCurrentValue().ToString())); 
                }
                return value;
            }
            set 
            {
                if (null == key || null == key.GetCurrentValue()) 
                { 
                    throw FxTrace.Exception.AsError( new ArgumentNullException("key"));
                } 
                if (this.instance.IsReadOnly)
                {
                    throw FxTrace.Exception.AsError( new InvalidOperationException(SR.CollectionIsReadOnly));
                } 
                ModelItem oldValue = null;
                if (this.modelItems.TryGetValue(key, out oldValue)) 
                { 
                    this.modelTreeManager.DictionaryEdit(this, key, value, oldValue);
                } 
                else
                {
                    this.modelTreeManager.DictionaryAdd(this, key, value);
                } 
            }
        } 
 
        public override ModelItem this[object key]
        { 
            get
            {
                if (null == key)
                { 
                    throw FxTrace.Exception.AsError( new ArgumentNullException("key"));
                } 
 
                ModelItem keyItem = this.KeyAsModelItem(key, false);
 
                if (null == keyItem)
                {
                    throw FxTrace.Exception.AsError( new KeyNotFoundException(key.ToString()));
                } 
                return this[keyItem];
            } 
            set 
            {
                if (null == key) 
                {
                    throw FxTrace.Exception.AsError( new ArgumentNullException("key"));
                }
 
                if (this.instance.IsReadOnly)
                { 
                    throw FxTrace.Exception.AsError( new InvalidOperationException(SR.CollectionIsReadOnly)); 
                }
 
                ModelItem keyItem = this.KeyAsModelItem(key, true);

                this[keyItem] = value;
            } 
        }
 
        public override void Add(ModelItem key, ModelItem value) 
        {
            if (null == key) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("key"));
            }
            if (this.instance.IsReadOnly) 
            {
                throw FxTrace.Exception.AsError( new InvalidOperationException(SR.CollectionIsReadOnly)); 
            } 
            this.modelTreeManager.DictionaryAdd(this, key, value);
        } 

        public override ModelItem Add(object key, object value)
        {
            if (null == key) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("key")); 
            } 
            if (this.instance.IsReadOnly)
            { 
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CollectionIsReadOnly));
            }
            ModelItem keyModelItem = key as ModelItem ?? this.WrapObject(key);
            ModelItem valueModelItem = value as ModelItem ?? this.WrapObject(value); 
            this.Add(keyModelItem, valueModelItem);
            return valueModelItem; 
        } 

        public override void Clear() 
        {
            this.modelTreeManager.DictionaryClear(this);
        }
 
        public override bool ContainsKey(ModelItem key)
        { 
            if (null == key) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("key")); 
            }
            return this.modelItems.Keys.Contains(key);
        }
 
        public override bool ContainsKey(object key)
        { 
            if (null == key) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("key")); 
            }
            if (typeof(ModelItem).IsAssignableFrom(key.GetType()))
            {
                return this.ContainsKey(key as ModelItem); 
            }
            return null != this.modelItems.Keys.SingleOrDefault(p => object.Equals(p.GetCurrentValue(), key)); 
        } 

        public override IEnumerator> GetEnumerator() 
        {
            return this.modelItems.GetEnumerator();
        }
 
        public override bool Remove(ModelItem key)
        { 
            if (null == key) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("key")); 
            }
            this.modelTreeManager.DictionaryRemove(this, key);
            return true;
        } 

        public override bool Remove(object key) 
        { 
            if (null == key)
            { 
                throw FxTrace.Exception.AsError( new ArgumentNullException("key"));
            }
            ModelItem keyItem = this.KeyAsModelItem(key, false);
 
            if (null != keyItem)
            { 
                return this.Remove(keyItem); 
            }
            return false; 
        }

        public override bool TryGetValue(ModelItem key, out ModelItem value)
        { 
            if (null == key)
            { 
                throw FxTrace.Exception.AsError( new ArgumentNullException("key")); 
            }
            return this.modelItems.TryGetValue(key, out value); 
        }

        public override bool TryGetValue(object key, out ModelItem value)
        { 
            if (null == key)
            { 
                throw FxTrace.Exception.AsError( new ArgumentNullException("key")); 
            }
            ModelItem keyItem = this.KeyAsModelItem(key, false); 
            if (null == keyItem)
            {
                value = null;
                return false; 
            }
            return this.TryGetValue(keyItem, out value); 
        } 

        public override ModelEditingScope BeginEdit(string description) 
        {
            return this.modelTreeManager.CreateEditingScope(description);
        }
 
        public override ModelEditingScope BeginEdit()
        { 
            return this.BeginEdit(null); 
        }
 
        public override object GetCurrentValue()
        {
            return this.instance.Value;
        } 

        #region IModelTreeItem Members 
 

        public void OnPropertyChanged(string propertyName) 
        {
            if (null != this.PropertyChanged)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
            }
        } 
 
        void IModelTreeItem.SetParent(ModelItem dataModelItem)
        { 
            if (!this.parents.Contains(dataModelItem))
            {
                this.parents.Add(dataModelItem);
            } 
        }
 
        void IModelTreeItem.SetSource(ModelProperty property) 
        {
            if (!this.sources.Contains(property)) 
            {
                // also check if the same parent.property is in the list as a different instance of oldModelProperty
                ModelProperty foundProperty = this.sources.Find((modelProperty) => modelProperty.Name.Equals(property.Name) && property.Parent == modelProperty.Parent);
                if (foundProperty == null) 
                {
                    this.sources.Add(property); 
                } 
            }
        } 

        IList IModelTreeItem.SubNodesThatNeedBackLinkUpdate
        {
            get 
            {
                return this.subTreeNodesThatNeedBackLinkPatching; 
            } 
        }
 
        public void SetCurrentView(DependencyObject view)
        {
            this.view = view;
        } 

        #endregion 
 
        void IModelTreeItem.RemoveParent(ModelItem oldParent)
        { 
            if (this.parents.Contains(oldParent))
            {
                this.parents.Remove(oldParent);
            } 
        }
 
        void IModelTreeItem.RemoveSource(ModelProperty oldModelProperty) 
        {
            if (this.sources.Contains(oldModelProperty)) 
            {
                this.sources.Remove(oldModelProperty);
            }
            else 
            {
                // also check if the same parent.property is in the list as a different instance of oldModelProperty 
                ModelProperty foundProperty = this.sources.Find((modelProperty) => modelProperty.Name.Equals(oldModelProperty.Name) && modelProperty.Parent == oldModelProperty.Parent); 
                if (foundProperty != null)
                { 
                    this.sources.Remove(foundProperty);
                }
                else
                { 
                    Fx.Assert("Trying to call RemoveSource() on modelItem that is not parented by oldModelProperty");
                } 
            } 
        }
 


        internal void EditCore(ModelItem key, ModelItem value)
        { 
            Fx.Assert(this.instance != null, "instance should not be null");
            if (key.Parent != this) 
            { 
                ((IModelTreeItem)key).SetParent(this);
            } 
            if (null != value && value.Parent != this)
            {
                ((IModelTreeItem)value).SetParent(this);
            } 
            this.instance[key.GetCurrentValue()] = null != value ? value.GetCurrentValue() : null;
            ModelItem oldValue = this.modelItems[key]; 
            this.modelItems[key] = value; 
            if (null != this.CollectionChanged)
            { 
                this.CollectionChanged(this,
                    new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace,
                    new KeyValuePair(key, value),
                    new KeyValuePair(key, oldValue))); 
            }
        } 
 
        internal void AddCore(ModelItem key, ModelItem value)
        { 
            Fx.Assert(this.instance != null, "instance should not be null");
            if (key.Parent != this)
            {
                ((IModelTreeItem)key).SetParent(this); 
            }
            if (null != value && value.Parent != this) 
            { 
                ((IModelTreeItem)value).SetParent(this);
            } 
            this.instance.Add(key.GetCurrentValue(), null != value ? value.GetCurrentValue() : null);
            this.modelItems.Add(key, value);
            if (null != this.CollectionChanged)
            { 
                this.CollectionChanged(this,
                    new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, 
                    new KeyValuePair(key, value))); 
            }
        } 

        internal void ClearCore()
        {
            Fx.Assert(this.instance != null, "instance should not be null"); 
            IList removed = this.modelItems.ToList>();
            this.instance.Clear(); 
            this.modelItems.Clear(); 
            if (null != this.CollectionChanged)
            { 
                this.CollectionChanged(this,
                    new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed));
            }
        } 

        internal void RemoveCore(ModelItem key) 
        { 
            Fx.Assert(this.instance != null, "instance should not be null");
            ModelItem value = this.modelItems[key]; 
            this.modelItems.Remove(key);
            this.instance.Remove(key.GetCurrentValue());
            if (null != this.CollectionChanged)
            { 
                this.CollectionChanged(this,
                    new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new KeyValuePair(key, value))); 
            } 
        }
 
        void UpdateInstance()
        {
            IEnumerator dictionaryEnumerator = this.instance.GetEnumerator();
            while (dictionaryEnumerator.MoveNext()) 
            {
                object current = dictionaryEnumerator.Current; 
 
                ModelItem key = this.WrapObject(instance.GetKeyFromCurrent(current));
                ModelItem value = this.WrapObject(instance.GetValueFromCurrent(current)); 
                if (key != null)
                {
                    this.modelItems.Add(key, value);
                } 
            }
        } 
 
        ModelItem WrapObject(object value)
        { 
            return this.ModelTreeManager.WrapAsModelItem(this, value);
        }

        ModelItem KeyAsModelItem(object value, bool createNew) 
        {
            ModelItem result = (value as ModelItem) ?? (ModelItem)this.modelItems.Keys.SingleOrDefault 
                (p => object.Equals(p.GetCurrentValue(), value)); 
            if (createNew && null == result)
            { 
                result = WrapObject(value);
            }
            return result;
        } 

        sealed class DictionaryWrapper 
        { 
            object instance;
            bool isDictionary = false; 
            PropertyInfo isReadOnlyProperty;
            PropertyInfo countProperty;
            PropertyInfo indexingProperty;
            MethodInfo addMethod; 
            MethodInfo removeMethod;
            MethodInfo clearMethod; 
            MethodInfo getEnumeratorMethod; 
            PropertyInfo keyProperty;
            PropertyInfo valueProperty; 

            public DictionaryWrapper(object instance)
            {
                this.instance = instance; 
                if (instance is IDictionary)
                { 
                    this.isDictionary = true; 
                    Type keyValuePairType = typeof(KeyValuePair);
                } 
                else
                {
                    Type instanceType = instance.GetType();
                    instanceType.FindInterfaces(this.GetDictionaryInterface, null); 
                }
            } 
 
            public object Value
            { 
                get { return this.instance; }
            }

            public bool IsReadOnly 
            {
                get 
                { 
                    return (this.isDictionary ? ((IDictionary)instance).IsReadOnly : (bool)this.isReadOnlyProperty.GetValue(this.instance, null));
                } 
            }

            public int Count
            { 
                get
                { 
                    return (this.isDictionary ? ((IDictionary)instance).Count : (int)this.countProperty.GetValue(this.instance, null)); 
                }
            } 

            [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification="This is intended for use through reflection")]
            public object this[object key]
            { 
                get
                { 
                    if (this.isDictionary) 
                    {
                        return ((IDictionary)instance)[key]; 
                    }
                    else
                    {
                        return this.indexingProperty.GetValue(this.instance, new object[] { key }); 
                    }
                } 
                set 
                {
                    if (this.isDictionary) 
                    {
                        ((IDictionary)instance)[key] = value;
                    }
                    else 
                    {
                        this.indexingProperty.SetValue(this.instance, value, new object[] { key }); 
                    } 
                }
            } 

            public object GetKeyFromCurrent(object keyValuePair)
            {
                if (isDictionary) 
                {
                    return ((DictionaryEntry)keyValuePair).Key; 
                } 
                else
                { 
                    return this.keyProperty.GetValue(keyValuePair, null);
                }
            }
 
            public object GetValueFromCurrent(object keyValuePair)
            { 
                if (isDictionary) 
                {
                    return ((DictionaryEntry)keyValuePair).Value; 
                }
                else
                {
                    return this.valueProperty.GetValue(keyValuePair, null); 
                }
            } 
 

            bool GetDictionaryInterface(Type type, object dummy) 
            {
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
                {
                    this.addMethod = type.GetMethod("Add"); 
                    this.removeMethod = type.GetMethod("Remove");
                    this.indexingProperty = type.GetProperty("Item"); 
                    return true; 
                }
                if (type.IsGenericType && 
                    type.GetGenericArguments()[0].IsGenericType &&
                    type.GetGenericArguments()[0].GetGenericTypeDefinition() == typeof(KeyValuePair<,>) &&
                    type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
                { 
                    Type keyValuePairType = type.GetGenericArguments()[0];
                    this.keyProperty = keyValuePairType.GetProperty("Key"); 
                    this.valueProperty = keyValuePairType.GetProperty("Value"); 
                    this.getEnumeratorMethod = type.GetMethod("GetEnumerator");
                    return true; 
                }
                if (type.IsGenericType &&
                    type.GetGenericArguments()[0].IsGenericType &&
                    type.GetGenericArguments()[0].GetGenericTypeDefinition() == typeof(KeyValuePair<,>) && 
                    type.GetGenericTypeDefinition() == typeof(ICollection<>))
                { 
                    this.isReadOnlyProperty = type.GetProperty("IsReadOnly"); 
                    this.countProperty = type.GetProperty("Count");
                    this.clearMethod = type.GetMethod("Clear"); 
                }
                return false;
            }
 

            public void Add(object key, object value) 
            { 
                if (this.isDictionary)
                { 
                    ((IDictionary)instance).Add(key, value);
                }
                else
                { 
                    this.addMethod.Invoke(this.instance, new object[] { key, value });
                } 
            } 

            public void Clear() 
            {
                if (this.isDictionary)
                {
                    ((IDictionary)instance).Clear(); 
                }
                else 
                { 
                    this.clearMethod.Invoke(this.instance, null);
                } 
            }

            public IEnumerator GetEnumerator()
            { 
                if (this.isDictionary)
                { 
                    return ((IDictionary)instance).GetEnumerator(); 
                }
                else 
                {
                    return (IEnumerator)this.getEnumeratorMethod.Invoke(this.instance, null);
                }
            } 

            public void Remove(object key) 
            { 
                if (this.isDictionary)
                { 
                    ((IDictionary)instance).Remove(key);
                }
                else
                { 
                    this.removeMethod.Invoke(this.instance, new object[] { key });
                } 
            } 

 
        }

        AttributeCollection ICustomTypeDescriptor.GetAttributes()
        { 
            return this.Attributes;
        } 
 
        string ICustomTypeDescriptor.GetClassName()
        { 
            return TypeDescriptor.GetClassName(this);
        }

        string ICustomTypeDescriptor.GetComponentName() 
        {
            return TypeDescriptor.GetComponentName(this); 
        } 

        TypeConverter ICustomTypeDescriptor.GetConverter() 
        {
            return ModelUtilities.GetConverter(this);
        }
 
        EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
        { 
            // we dont support events; 
            return null;
        } 

        PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
        {
            return ModelUtilities.GetDefaultProperty(this); 
        }
 
        object ICustomTypeDescriptor.GetEditor(Type editorBaseType) 
        {
            // we dont support editors 
            return null;
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) 
        {
            // we dont support events; 
            return null; 
        }
 
        EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
        {
            // we dont support events;
            return null; 
        }
 
        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) 
        {
            return ModelUtilities.WrapProperties(this); 
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
        { 
            // get model properties
            List properties = new List(); 
 

            foreach (PropertyDescriptor modelPropertyDescriptor in ModelUtilities.WrapProperties(this)) 
            {
                properties.Add(modelPropertyDescriptor);
            }
 
            // try to see if there are pseudo builtin properties for this type.
            AttachedPropertiesService AttachedPropertiesService = this.modelTreeManager.Context.Services.GetService(); 
            if (AttachedPropertiesService != null) 
            {
                foreach (AttachedProperty AttachedProperty in AttachedPropertiesService.GetAttachedProperties(this.itemType)) 
                {
                    properties.Add(new AttachedPropertyDescriptor(AttachedProperty, this));
                }
            } 
            return new PropertyDescriptorCollection(properties.ToArray(), true);
        } 
 
        object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
        { 
            return this;
        }

    } 
}

// 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