ModelTreeManager.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 / ModelTreeManager.cs / 1305376 / ModelTreeManager.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------

namespace System.Activities.Presentation.Model 
{
    using System.Activities.Presentation; 
    using System.Activities.Presentation.Hosting; 
    using System.Activities.Presentation.Services;
    using System.Activities.Presentation.View; 
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq; 
    using System.ComponentModel;
    using System.Runtime; 
    using System.Diagnostics.CodeAnalysis; 
    using System.Activities.Presentation.Internal.PropertyEditing;
 

    // This class manages the model tree, provides the root model item and the modelservice
    // This also provides syncing the model tree with the xaml text
    // The model service is publishes on the editing context passed to the constructor. 

    [Fx.Tag.XamlVisible(false)] 
    public class ModelTreeManager 
    {
        internal ModelServiceImpl modelService; 
        EditingContext context;
        // The value of this dictionary is a WeakReference to ModelItem.
        // This need to be a WeakReference because if the ModelItem has a strong reference, it
        // will have a strong reference to the underlying object instance as well. 
        WeakKeyDictionary objectMap;
        ModelItem rootItem; 
        Stack editingScopes; 
        bool trackChanges = true;
        FeatureManager featureManager; 

        public ModelTreeManager(EditingContext context)
        {
            if (context == null) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("context")); 
            } 
            this.context = context;
            objectMap = new WeakKeyDictionary(new ObjectEqualityComparer()); 
            editingScopes = new Stack();
        }

 
        public event EventHandler EditingScopeCompleted;
 
        public ModelItem Root 
        {
            get 
            {
                return this.rootItem;
            }
        } 

        internal EditingContext Context 
        { 
            get
            { 
                return this.context;
            }
        }
 
        FeatureManager FeatureManager
        { 
            get 
            {
                if (this.featureManager == null) 
                {
                    this.featureManager = this.context.Services.GetService();
                }
                return this.featureManager; 
            }
        } 
 
        internal bool RedoUndoInProgress
        { 
            get
            {
                return !this.trackChanges;
            } 
        }
 
        internal void StartTracking() 
        {
            trackChanges = true; 
        }

        internal void StopTracking()
        { 
            trackChanges = false;
        } 
 
        public ModelItem CreateModelItem(ModelItem parent, object instance)
        { 
            if (instance == null)
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("instance"));
            } 
            ModelItem retval;
 
            Type instanceType = instance.GetType(); 
            object[] result = new object[2] { false, false };
 
            Type[] interfaces = instanceType.FindInterfaces(ModelTreeManager.CheckInterface, result);

            bool isList = (bool)result[0];
            bool isDictionary = (bool)result[1]; 

            if (isDictionary) 
            { 
                foreach (Type type in interfaces)
                { 
                    if (type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
                    {
                        // To expose one more property, a collection of MutableKeyValuePairs, to the model tree.
                        TypeDescriptor.AddProvider(new DictionaryTypeDescriptionProvider(instanceType), instance); 
                        break;
                    } 
                } 

                ModelItemDictionary modelItem = new ModelItemDictionaryImpl(this, instance.GetType(), instance, parent); 
                retval = modelItem;
            }
            else if (isList)
            { 
                ModelItemCollectionImpl modelItem = new ModelItemCollectionImpl(this, instance.GetType(), instance, parent);
                retval = modelItem; 
            } 
            else
            { 
                retval = new ModelItemImpl(this, instance.GetType(), instance, parent);
            }
            if (!((instance is ValueType) || (instance is string)))
            { 
                //
                // ValueType do not have a concept of shared reference, they are always copied. 
                // strings are immutatable, therefore the risk of making all shared string references to different 
                // string ModelItems is low.
                // 
                // To special case string is because underlying OM are sharing string objects for DisplayName across
                // Different activity object instances. These shared references is causing memory leak because of bugs.
                //
                // We will need to fix these issues in Beta2. 
                //
                objectMap[instance] = new WeakReference(retval); 
            } 

            if (this.FeatureManager != null) 
            {
                this.FeatureManager.InitializeFeature(instance.GetType());
            }
            return retval; 
        }
 
        static bool CheckInterface(Type type, object result) 
        {
            object[] values = (object[])result; 
            if (typeof(IList).IsAssignableFrom(type))
            {
                values[0] = true;
                return true; 
            }
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IList < > )) 
            { 
                values[0] = true;
                return true; 
            }
            if (typeof(IDictionary).IsAssignableFrom(type))
            {
                values[1] = true; 
                return true;
            } 
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary <, > )) 
            {
                values[1] = true; 
                return true;
            }
            return false;
        } 

        public void Load(object rootInstance) 
        { 
            if (rootInstance == null)
            { 
                throw FxTrace.Exception.AsError( new ArgumentNullException("rootInstance"));
            }
            objectMap.Clear();
 
            this.rootItem = WrapAsModelItem(null, rootInstance);
            if (this.modelService == null) 
            { 
                this.modelService = new ModelServiceImpl(this);
                this.context.Services.Publish(modelService); 
            }
        }

        // This methods clears the value of a property , if the property is 
        // a reference type then its set to null, if its a value type the
        // property value is reset to the default. this also clears the sub modelitem corresponding 
        // to the old value from the parent modelitem's modelPropertyStore. 
        internal void ClearValue(ModelPropertyImpl modelProperty)
        { 
            Fx.Assert(modelProperty != null, "modelProperty should not be null");
            Fx.Assert(modelProperty.Parent is IModelTreeItem, "modelProperty.Parent should be an IModelTreeItem");
            ModelItem newValueModelItem = null;
            newValueModelItem = WrapAsModelItem(null, modelProperty.DefaultValue); 
            PropertyChange propertyChange = new PropertyChange()
                { 
                    Owner = modelProperty.Parent, 
                    PropertyName = modelProperty.Name,
                    OldValue = modelProperty.Value, 
                    NewValue = newValueModelItem,
                    ModelTreeManager = this
                };
            AddToCurrentEditingScope(propertyChange); 
        }
 
        internal void CollectionAdd(ModelItemCollectionImpl dataModelItemCollection, ModelItem item) 
        {
            CollectionInsert(dataModelItemCollection, -1, item); 
        }

        internal void CollectionInsert(ModelItemCollectionImpl dataModelItemCollection, int index, ModelItem item)
        { 
            Fx.Assert(dataModelItemCollection != null,"collection should not be null");
            CollectionChange change = new CollectionChange() 
                { 
                    Collection = dataModelItemCollection,
                    Item = item, 
                    Index = index,
                    ModelTreeManager = this,
                    Operation = CollectionChange.OperationType.Insert
                }; 
            AddToCurrentEditingScope(change);
        } 
 
        internal void CollectionClear(ModelItemCollectionImpl modelItemCollectionImpl)
        { 
            Fx.Assert(modelItemCollectionImpl != null,"collection should not be null");
            Fx.Assert(this.modelService != null, "modelService should not be null");
            List removedItems = new List();
            removedItems.AddRange(modelItemCollectionImpl); 
            using (ModelEditingScope editingScope = CreateEditingScope(SR.CollectionClearEditingScopeDescription))
            { 
                foreach (ModelItem modelItem in removedItems) 
                {
                    this.CollectionRemove(modelItemCollectionImpl, modelItem); 
                }
                editingScope.Complete();
            }
            this.modelService.OnModelItemsRemoved(removedItems); 
        }
 
        internal void NotifyCollectionInsert(ModelItem item) 
        {
            this.modelService.OnModelItemAdded(item); 
        }

        internal void CollectionRemove(ModelItemCollectionImpl dataModelItemCollection, ModelItem item)
        { 
            CollectionRemove(dataModelItemCollection, item, -1);
        } 
 
        internal void CollectionRemoveAt(ModelItemCollectionImpl dataModelItemCollection, int index)
        { 
            ModelItem item = dataModelItemCollection[index];
            CollectionRemove(dataModelItemCollection, item, index);
        }
 
        void CollectionRemove(ModelItemCollectionImpl dataModelItemCollection, ModelItem item, int index)
        { 
            Fx.Assert(dataModelItemCollection != null,"collection should not be null"); 
            CollectionChange change = new CollectionChange()
                { 
                    Collection = dataModelItemCollection,
                    Item = item,
                    Index = index,
                    ModelTreeManager = this, 
                    Operation = CollectionChange.OperationType.Delete
                }; 
            AddToCurrentEditingScope(change); 
        }
 
        internal void NotifyCollectionRemove(ModelItem item)
        {
            this.modelService.OnModelItemRemoved(item);
        } 

        internal void DictionaryClear(ModelItemDictionaryImpl modelDictionary) 
        { 
            Fx.Assert(modelDictionary != null,"dictionary should not be null");
            Fx.Assert(this.modelService != null, "modelService should not be null"); 
            ModelItem[] keys = modelDictionary.Keys.ToArray();

            using (ModelEditingScope editingScope = CreateEditingScope(SR.DictionaryClearEditingScopeDescription))
            { 
                foreach (ModelItem key in keys)
                { 
                    this.DictionaryRemove(modelDictionary, key); 
                }
                editingScope.Complete(); 
            }
        }

        internal void DictionaryEdit(ModelItemDictionaryImpl dataModelItemDictionary, ModelItem key, ModelItem newValue, ModelItem oldValue) 
        {
            Fx.Assert(dataModelItemDictionary != null,"dictionary should not be null"); 
            Fx.Assert(this.modelService != null, "modelService should not be null"); 
            DictionaryEditChange change = new DictionaryEditChange()
                { 
                    Dictionary = dataModelItemDictionary,
                    Key = key,
                    NewValue = newValue,
                    OldValue = oldValue, 
                    ModelTreeManager = this
                }; 
            AddToCurrentEditingScope(change); 
        }
 
        internal void DictionaryAdd(ModelItemDictionaryImpl dataModelItemDictionary, ModelItem key, ModelItem value)
        {
            Fx.Assert(dataModelItemDictionary != null, "dictionary should not be null");
            Fx.Assert(this.modelService != null, "modelService should not be null"); 
            DictionaryChange change = new DictionaryChange()
                { 
                    Dictionary = dataModelItemDictionary, 
                    Key = key,
                    Value = value, 
                    Operation = DictionaryChange.OperationType.Insert,
                    ModelTreeManager = this
                };
            AddToCurrentEditingScope(change); 
        }
 
        internal void DictionaryRemove(ModelItemDictionaryImpl dataModelItemDictionary, ModelItem key) 
        {
            Fx.Assert(dataModelItemDictionary != null, "dictionary should not be null"); 
            Fx.Assert(this.modelService != null, "modelService should not be null");
            ModelItem value = dataModelItemDictionary[key];
            DictionaryChange change = new DictionaryChange()
                { 
                    Dictionary = dataModelItemDictionary,
                    Key = key, 
                    Value = value, 
                    Operation = DictionaryChange.OperationType.Delete,
                    ModelTreeManager = this 
                };
            AddToCurrentEditingScope(change);

        } 

        internal IEnumerable Find(ModelItem startingItem, Predicate matcher, bool skipCollapsedAndUnrootable) 
        { 
            Fx.Assert(startingItem != null, "starting item should not be null");
            Fx.Assert(matcher != null, "matching predicate should not be null"); 
            WorkflowViewService viewService = this.Context.Services.GetService() as WorkflowViewService;
            if (skipCollapsedAndUnrootable)
            {
                Fx.Assert(viewService != null, "ViewService must be available in order to skip exploring ModelItems whose views are collapsed."); 
            }
 
            List foundItems = new List(); 
            Queue modelItems = new Queue();
            modelItems.Enqueue(startingItem); 
            HashSet alreadyVisited = new HashSet();
            while (modelItems.Count > 0)
            {
                ModelItem currentModelItem = modelItems.Dequeue(); 
                if (currentModelItem == null)
                { 
                    continue; 
                }
 
                if (matcher(currentModelItem.ItemType))
                {
                    foundItems.Add(currentModelItem);
                } 

                ModelItemCollection collection = currentModelItem as ModelItemCollection; 
                if (collection != null) 
                {
                    foreach (ModelItem modelItem in collection) 
                    {
                        if (modelItem != null && !alreadyVisited.Contains(modelItem))
                        {
                            alreadyVisited.Add(modelItem); 
                            modelItems.Enqueue(modelItem);
                        } 
                    } 
                }
                else 
                {
                    ModelItemDictionary dictionary = currentModelItem as ModelItemDictionary;
                    if (dictionary != null)
                    { 
                        foreach (KeyValuePair kvp in dictionary)
                        { 
                            ModelItem miKey = kvp.Key; 
                            if (miKey != null && !alreadyVisited.Contains(miKey))
                            { 
                                alreadyVisited.Add(miKey);
                                modelItems.Enqueue(miKey);
                            }
 
                            ModelItem miValue = kvp.Value;
                            if (miValue != null && !alreadyVisited.Contains(miValue)) 
                            { 
                                alreadyVisited.Add(miValue);
                                modelItems.Enqueue(miValue); 
                            }
                        }
                    }
                } 

                if (!skipCollapsedAndUnrootable || !typeof(WorkflowViewElement).IsAssignableFrom(viewService.GetDesignerType(currentModelItem.ItemType)) || 
                    ViewUtilities.IsViewExpanded(currentModelItem, this.Context) && viewService.ShouldAppearOnBreadCrumb(currentModelItem, true)) 
                {
                    ModelPropertyCollection modelProperties = currentModelItem.Properties; 
                    foreach (ModelProperty property in modelProperties)
                    {
                        // we dont want to even try to get the value for a value type property
                        // because that will create a new modelitem everytime. 

                        // System.Type has properties that throw when we try to get value 
                        // we dont want to expand system.type further during a search. 
                        if (property.PropertyType.IsAssignableFrom(typeof(Type)) || property.PropertyType.IsValueType)
                        { 
                            continue;
                        }

                        else 
                        {
                            if (property.Value != null && !alreadyVisited.Contains(property.Value)) 
                            { 
                                alreadyVisited.Add(property.Value);
                                modelItems.Enqueue(property.Value); 
                            }
                        }
                    }
                } 
            }
            return foundItems; 
        } 

        internal ModelItem FindFirst(ModelItem startingItem, Predicate matcher) 
        {
            Fx.Assert(startingItem != null, "starting item should not be null");
            Fx.Assert(matcher != null, "matching predicate should not be null");
            ModelItem foundItem = null; 
            Queue modelItems = new Queue();
            modelItems.Enqueue(startingItem); 
            HashSet alreadyVisited = new HashSet(); 
            while (modelItems.Count > 0)
            { 
                ModelItem currentModelItem = modelItems.Dequeue();
                if (currentModelItem == null)
                {
                    continue; 
                }
 
                if (matcher(currentModelItem)) 
                {
                    foundItem = currentModelItem; 
                    break;
                }

                ModelItemCollection collection = currentModelItem as ModelItemCollection; 
                if (collection != null)
                { 
                    foreach (ModelItem modelItem in collection) 
                    {
                        if (modelItem != null && !alreadyVisited.Contains(modelItem)) 
                        {
                            alreadyVisited.Add(modelItem);
                            modelItems.Enqueue(modelItem);
                        } 
                    }
                } 
                else 
                {
                    ModelItemDictionary dictionary = currentModelItem as ModelItemDictionary; 
                    if (dictionary != null)
                    {
                        foreach (KeyValuePair kvp in dictionary)
                        { 
                            ModelItem miKey = kvp.Key;
                            if (miKey != null && !alreadyVisited.Contains(miKey)) 
                            { 
                                alreadyVisited.Add(miKey);
                                modelItems.Enqueue(miKey); 
                            }

                            ModelItem miValue = kvp.Value;
                            if (miValue != null && !alreadyVisited.Contains(miValue)) 
                            {
                                alreadyVisited.Add(miValue); 
                                modelItems.Enqueue(miValue); 
                            }
                        } 
                    }
                }

 
                ModelPropertyCollection modelProperties = currentModelItem.Properties;
                foreach (ModelProperty property in modelProperties) 
                { 
                    // we dont want to even try to get the value for a value type property
                    // because that will create a new modelitem everytime. 

                    // System.Type has properties that throw  when we try to get value
                    // we dont want to expand system.type further during a search.
                    if (property.PropertyType.IsAssignableFrom(typeof(Type)) || property.PropertyType.IsValueType) 
                    {
                        continue; 
                    } 

                    else 
                    {
                        if (property.Value != null && !alreadyVisited.Contains(property.Value))
                        {
                            alreadyVisited.Add(property.Value); 
                            modelItems.Enqueue(property.Value);
                        } 
                    } 
                }
            } 
            return foundItem;
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", 
          Justification = "If the property getter threw here we dont want to crash, we just dont want to wrap that property value")]
        [SuppressMessage("Reliability", "Reliability108:IsFatalRule", 
            Justification = "If the property getter threw here we dont want to crash, we just dont want to wrap that property value")] 
        internal ModelItem GetValue(ModelPropertyImpl dataModelProperty)
        { 
            Fx.Assert(dataModelProperty != null,"modelproperty should not be null");
            Fx.Assert(dataModelProperty.Parent is IModelTreeItem, "modelproperty.Parent should be an IModelTreeItem");
            IModelTreeItem parent = (IModelTreeItem)dataModelProperty.Parent;
            ModelItem value; 

            // always reevaluate attached properties. the cache in attached properties case is only to remember the old value. 
            if (!dataModelProperty.IsAttached && parent.ModelPropertyStore.ContainsKey(dataModelProperty.Name)) 
            {
                value = parent.ModelPropertyStore[dataModelProperty.Name]; 
            }
            // Create a ModelItem on demand for the value of the property.
            else
            { 
                try
                { 
                    value = WrapAsModelItem(null, dataModelProperty.PropertyDescriptor.GetValue(parent.ModelItem.GetCurrentValue())); 
                }
                catch (System.Exception) 
                {
                    // GetValue throws an exception if Value is not available
                    value = null;
                } 
                if (value != null)
                { 
                    if (!dataModelProperty.IsAttached) 
                    {
                        parent.ModelPropertyStore.Add(dataModelProperty.Name, value); 
                    }
                    ((IModelTreeItem)value).SetSource(dataModelProperty);
                }
            } 
            return value;
        } 
 
        internal ModelItem SetValue(ModelPropertyImpl modelProperty, object value)
        { 
            Fx.Assert(modelProperty != null, "modelProperty should not be null");
            ModelItem newValueModelItem = null;

            RefreshPropertiesAttribute refreshPropertiesAttribute = ExtensibilityAccessor.GetAttribute(modelProperty.Attributes); 
            if (refreshPropertiesAttribute != null && refreshPropertiesAttribute.RefreshProperties == RefreshProperties.All)
            { 
                ((IModelTreeItem)modelProperty.Parent).ModelPropertyStore.Clear(); 
            }
 
            if (value is ModelItem)
            {
                newValueModelItem = (ModelItem)value;
            } 
            else
            { 
                newValueModelItem = WrapAsModelItem(null, value); 
            }
            // dont do deferred updates for attached properties 
            if (modelProperty.IsAttached)
            {
                modelProperty.SetValueCore(newValueModelItem);
            } 
            else
            { 
                PropertyChange propertyChange = new PropertyChange() 
                {
                    Owner = modelProperty.Parent, 
                    PropertyName = modelProperty.Name,
                    OldValue = modelProperty.Value,
                    NewValue = newValueModelItem,
                    ModelTreeManager = this 
                };
                AddToCurrentEditingScope(propertyChange); 
            } 

 
            return newValueModelItem;
        }

 

        internal void AddToCurrentEditingScope(Change change) 
        { 
            EditingScope editingScope;
            if (editingScopes.Count > 0) 
            {
                editingScope = (EditingScope)editingScopes.Peek();
                // Automatic generated change during apply changes of Redo/Undo should be ignored.
                if (!RedoUndoInProgress) 
                {
                    editingScope.Changes.Add(change); 
                } 
            }
            else 
            {
                //edit operation without editingscope create an editing scope and complete it immediately.
                editingScope = CreateEditingScope(change.Description);
                editingScope.Changes.Add(change); 
                try
                { 
                    editingScope.Complete(); 
                }
                catch 
                {
                    editingScope.Revert();
                    throw;
                } 

            } 
 
        }
 
        internal EditingScope CreateEditingScope(string description)
        {
            EditingScope editingScope;
            EditingScope outerScope = editingScopes.Count > 0 ? (EditingScope)editingScopes.Peek() : null; 
            editingScope = new EditingScope(this, outerScope);
            editingScope.Description = description; 
            editingScopes.Push(editingScope); 
            return editingScope;
        } 

        internal void NotifyPropertyChange(ModelPropertyImpl dataModelProperty)
        {
            modelService.OnModelPropertyChanged(dataModelProperty); 
        }
 
 

 

        internal void SyncModelAndText()
        {
            // Place holder for xaml generation ModelTreeManager now is instance only. 
        }
 
        internal ModelItem WrapAsModelItem(ModelItem parent, object instance) 
        {
            ModelItem modelItem = GetModelItem(instance); 
            //first, check if model item exists - if it does, check if its parent needs to be set properly.
            if (instance != null && modelItem !=null)
            {
                if (null != parent) 
                {
                    ((IModelTreeItem)modelItem).SetParent(parent); 
                } 
            }
            //if one doesn't exists - create new one 
            else if (null != instance && null == modelItem)
            {
                modelItem = CreateModelItem(parent, instance);
            } 
            return modelItem;
        } 
 
        internal ModelItem GetModelItem(object instance)
        { 
            if (instance == null)
            {
                return null;
            } 
            ModelItem modelItem = null;
            WeakReference mappedModelItem = null; 
            objectMap.TryGetValue(instance, out mappedModelItem); 
            if (mappedModelItem != null)
            { 
                modelItem = (ModelItem)mappedModelItem.Target;
            }
            return modelItem;
        } 

        internal void ReAddModelItemToModelTree(ModelItem modelItem) 
        { 
            if (modelItem != null)
            { 
                IList modelItemsThatNeedBackLinkUpdate = ((IModelTreeItem)modelItem).SubNodesThatNeedBackLinkUpdate;
                if (modelItemsThatNeedBackLinkUpdate.Count > 0)
                {
                    foreach (ModelItem modelItemThatNeedsBackLinkUpdate in modelItemsThatNeedBackLinkUpdate) 
                    {
                        UpdateBackLinksForDependentsOf(modelItemThatNeedsBackLinkUpdate); 
                    } 
                    modelItemsThatNeedBackLinkUpdate.Clear();
                } 
            }
        }

        private void UpdateBackLinksForDependentsOf(ModelItem modelItem) 
        {
            //restore property backlinks 
 
            foreach (string propertyName in ((IModelTreeItem)modelItem).ModelPropertyStore.Keys)
            { 
                ModelItem propertyValueModelItem = ((IModelTreeItem)modelItem).ModelPropertyStore[propertyName];
                if(propertyValueModelItem != null)
                {
                    ((IModelTreeItem)propertyValueModelItem).SetSource(modelItem.Properties[propertyName]); 
                }
            } 
 
            // restore collection backlinks
 
            ModelItemCollection modelItemCollection = modelItem as ModelItemCollection;
            if (modelItemCollection != null)
            {
                foreach(ModelItem collectionChild in modelItemCollection) 
                {
                    if(collectionChild != null) 
                    { 
                        ((IModelTreeItem)collectionChild).SetParent(modelItemCollection);
                    } 
                }
            }

            // restore dictionary backlinks 

            ModelItemDictionary modelItemDictionary = modelItem as ModelItemDictionary; 
            if (modelItemDictionary != null) 
            {
                foreach (ModelItem keyModelItem in modelItemDictionary.Keys) 
                {
                    if (keyModelItem != null)
                    {
                        ((IModelTreeItem)keyModelItem).SetParent(modelItemDictionary); 
                    }
                } 
 
                foreach (ModelItem valueModelItem in modelItemDictionary.Values)
                { 
                    if (valueModelItem != null)
                    {
                        ((IModelTreeItem)valueModelItem).SetParent(modelItemDictionary);
                    } 
                }
            } 
 
        }
 
        internal void ReleaseModelItem(ModelItem oldValueModelItem, ModelItem parent)
        {
            Fx.Assert(oldValueModelItem != null, "old value modelItem should not be null");
            HashSet visited = new HashSet(); 
            Queue nodes = new Queue();
 
            nodes.Enqueue(new Dependency() { Parent = parent, Dependant = oldValueModelItem }); 
            while (nodes.Count > 0)
            { 
                Dependency dependency = nodes.Dequeue();
                if (HasNoOtherParents(dependency))
                {
                    // this node depends only on this parent, visit this. 
                    ModelItem currentModelItem = dependency.Dependant;
                    if (!visited.Contains(currentModelItem)) 
                    { 
                        visited.Add(currentModelItem);
                        foreach (ModelItem child in GetDependants(currentModelItem)) 
                        {
                            nodes.Enqueue(new Dependency() { Dependant = child, Parent = currentModelItem });
                        }
                    } 
                }
                else // This node has other references, dont dig any deeper, but remove its immediate backpointer to this parent. 
                { 
                    RemoveBackLink(dependency);
                    if (dependency.Dependant != oldValueModelItem) 
                    {
                        ((IModelTreeItem)oldValueModelItem).SubNodesThatNeedBackLinkUpdate.Add(dependency.Parent);
                    }
                } 
            }
 
 
        }
 
        private void RemoveBackLink(Dependency dependency)
        {
            // remove sources that have source.Parent == dependency.Parent
            var sourceBackLinks = from source in dependency.Dependant.Sources 
                where source.Parent == dependency.Parent
                select source; 
            foreach (ModelProperty sourceBackLink in sourceBackLinks.ToList()) 
            {
                ((IModelTreeItem)dependency.Dependant).RemoveSource(sourceBackLink); 
            }
            // remove collectionParents that equal dependency.Parent.
            ((IModelTreeItem)dependency.Dependant).RemoveParent(dependency.Parent);
        } 

 
        private IEnumerable GetDependants(ModelItem modelItem) 
        {
            List dependants = new List(); 

            // modelimpl- propertystore
            dependants.AddRange(((IModelTreeItem)modelItem).ModelPropertyStore.Values);
 
            // modelcolleciton - propertystore + items
            if (modelItem is ModelItemCollection) 
            { 
                dependants.AddRange((ModelItemCollection)modelItem);
            } 

                // modeldictionary - propertystore + keys + values;
            else if (modelItem is ModelItemDictionary)
            { 
                dependants.AddRange(((ModelItemDictionary)modelItem).Keys);
                dependants.AddRange(((ModelItemDictionary)modelItem).Values); 
            } 
            return dependants.Where(e => e != null);
        } 

        private bool HasNoOtherParents(Dependency dependency)
        {
            var otherParents = from parent in dependency.Dependant.Parents 
                where parent != dependency.Parent
                select parent; 
            return otherParents.Count() == 0; 
        }
 
        internal void OnEditingScopeCompleted(EditingScope modelEditingScopeImpl)
        {

            if (editingScopes.Contains(modelEditingScopeImpl)) 
            {
                editingScopes.Pop(); 
            } 
            // if the outer most scope completed notify listeners
            if (this.EditingScopeCompleted != null && editingScopes.Count == 0) 
            {
                this.EditingScopeCompleted(this, new EditingScopeEventArgs() { EditingScope = modelEditingScopeImpl });
            }
 
        }
 
        internal bool CanEditingScopeComplete(EditingScope modelEditingScopeImpl) 
        {
            ReadOnlyState readOnlyState = this.Context.Items.GetValue(); 
            return (modelEditingScopeImpl == editingScopes.Peek()) && (readOnlyState == null || !readOnlyState.IsReadOnly);
        }

        internal void OnEditingScopeReverted(EditingScope modelEditingScopeImpl) 
        {
            if (editingScopes.Contains(modelEditingScopeImpl)) 
            { 
                editingScopes.Pop();
            } 
        }

        class ObjectEqualityComparer : IEqualityComparer
        { 

            public int GetHashCode(object obj) 
            { 
                //If two reference objects are the same we return equal.
                //Object.GetHashCode() gurantees we return same hash code for same objects(equal references). 
                return obj.GetHashCode();
            }

            //We want to check reference equality for keys in ObjectMap. 
            //If the user overrides Equals method for their class we still want to use referential equality.
            public new bool Equals(object x, object y) 
            { 
                return object.ReferenceEquals(x, y);
            } 

        }

        class Dependency 
        {
            public ModelItem Parent { get; set; } 
            public ModelItem Dependant { get; set; } 
        }
 
        class DictionaryTypeDescriptionProvider : TypeDescriptionProvider
        {
            Type type;
            public DictionaryTypeDescriptionProvider(Type type) 
                : base(TypeDescriptor.GetProvider(type))
            { 
                this.type = type; 
            }
 
            public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
            {
                ICustomTypeDescriptor defaultDescriptor = base.GetTypeDescriptor(objectType, instance);
                return new DictionaryTypeDescriptor(defaultDescriptor, this.type); 
            }
        } 
 
        class DictionaryTypeDescriptor : CustomTypeDescriptor
        { 
            Type type;

            public DictionaryTypeDescriptor(ICustomTypeDescriptor parent, Type type)
                : base(parent) 
            {
                this.type = type; 
            } 

            // Expose one more property, a collection of MutableKeyValuePairs,  described by ItemsCollectionPropertyDescriptor 
            public override PropertyDescriptorCollection GetProperties()
            {
                return new PropertyDescriptorCollection(base.GetProperties().Cast()
                    .Union(new PropertyDescriptor[] {new ItemsCollectionPropertyDescriptor(type) }).ToArray()); 
            }
 
            // Expose one more property, a collection of MutableKeyValuePairs,  described by ItemsCollectionPropertyDescriptor 
            public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
            { 
                return new PropertyDescriptorCollection(base.GetProperties(attributes).Cast()
                    .Union(new PropertyDescriptor[] { new ItemsCollectionPropertyDescriptor(type) }).ToArray());
            }
        } 

        class ItemsCollectionPropertyDescriptor : PropertyDescriptor 
        { 
            Type dictionaryType;
            Type[] genericArguments; 
            Type kvpairType;
            Type itemType;
            Type propertyType;
 
            internal ItemsCollectionPropertyDescriptor(Type type)
                : base("ItemsCollection", null) 
            { 
                this.dictionaryType = type;
            } 

            Type[] GenericArguments
            {
                get 
                {
                    if (this.genericArguments == null) 
                    { 
                        object[] result = new object[2] { false, false };
                        Type[] interfaces = this.ComponentType.FindInterfaces(ModelTreeManager.CheckInterface, result); 
                        foreach (Type type in interfaces)
                        {
                            if (type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
                            { 
                                this.genericArguments = type.GetGenericArguments();
                                Fx.Assert(this.genericArguments.Length == 2, "this.genericArguments.Length should be = 2"); 
                                return this.genericArguments; 
                            }
                        } 
                        Debug.Fail("Cannot find generic arguments for IDictionary<,>.");
                    }
                    return this.genericArguments;
                } 
            }
 
            [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is intended for use through reflection")] 
            Type KVPairType
            { 
                get
                {
                    if (this.kvpairType == null)
                    { 
                        this.kvpairType = typeof(KeyValuePair<,>).MakeGenericType(this.GenericArguments);
                    } 
                    return this.kvpairType; 
                }
            } 

            [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is intended for use through reflection")]
            Type ItemType
            { 
                get
                { 
                    if (this.itemType == null) 
                    {
                        this.itemType = typeof(ModelItemKeyValuePair<,>).MakeGenericType(this.GenericArguments); 
                    }
                    return this.itemType;
                }
            } 

            public override Type ComponentType 
            { 
                get { return this.dictionaryType; }
            } 

            public override bool IsReadOnly
            {
                get 
                {
                    return true; 
                } 
            }
 
            public override Type PropertyType
            {
                get
                { 
                    if (this.propertyType == null)
                    { 
                        this.propertyType = typeof(DictionaryItemsCollection<,>).MakeGenericType(this.GenericArguments); 
                    }
                    return this.propertyType; 
                }
            }

            public override bool IsBrowsable 
            {
                get 
                { 
                    return false;
                } 
            }

            public override bool CanResetValue(object component)
            { 
                return false;
            } 
 
            public override object GetValue(object component)
            { 
                return Activator.CreateInstance(this.PropertyType, new object[] { component });
            }

            public override void ResetValue(object component) 
            {
                Debug.Fail("ResetValue is not implemented."); 
                throw FxTrace.Exception.AsError( new NotImplementedException()); 
            }
 
            public override void SetValue(object component, object value)
            {
                Debug.Fail("SetValue is not implemented.");
                throw FxTrace.Exception.AsError( new NotImplementedException()); 
            }
 
            public override bool ShouldSerializeValue(object component) 
            {
                return false; 
            }
        }
    }
} 

// 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.Activities.Presentation; 
    using System.Activities.Presentation.Hosting; 
    using System.Activities.Presentation.Services;
    using System.Activities.Presentation.View; 
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq; 
    using System.ComponentModel;
    using System.Runtime; 
    using System.Diagnostics.CodeAnalysis; 
    using System.Activities.Presentation.Internal.PropertyEditing;
 

    // This class manages the model tree, provides the root model item and the modelservice
    // This also provides syncing the model tree with the xaml text
    // The model service is publishes on the editing context passed to the constructor. 

    [Fx.Tag.XamlVisible(false)] 
    public class ModelTreeManager 
    {
        internal ModelServiceImpl modelService; 
        EditingContext context;
        // The value of this dictionary is a WeakReference to ModelItem.
        // This need to be a WeakReference because if the ModelItem has a strong reference, it
        // will have a strong reference to the underlying object instance as well. 
        WeakKeyDictionary objectMap;
        ModelItem rootItem; 
        Stack editingScopes; 
        bool trackChanges = true;
        FeatureManager featureManager; 

        public ModelTreeManager(EditingContext context)
        {
            if (context == null) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("context")); 
            } 
            this.context = context;
            objectMap = new WeakKeyDictionary(new ObjectEqualityComparer()); 
            editingScopes = new Stack();
        }

 
        public event EventHandler EditingScopeCompleted;
 
        public ModelItem Root 
        {
            get 
            {
                return this.rootItem;
            }
        } 

        internal EditingContext Context 
        { 
            get
            { 
                return this.context;
            }
        }
 
        FeatureManager FeatureManager
        { 
            get 
            {
                if (this.featureManager == null) 
                {
                    this.featureManager = this.context.Services.GetService();
                }
                return this.featureManager; 
            }
        } 
 
        internal bool RedoUndoInProgress
        { 
            get
            {
                return !this.trackChanges;
            } 
        }
 
        internal void StartTracking() 
        {
            trackChanges = true; 
        }

        internal void StopTracking()
        { 
            trackChanges = false;
        } 
 
        public ModelItem CreateModelItem(ModelItem parent, object instance)
        { 
            if (instance == null)
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("instance"));
            } 
            ModelItem retval;
 
            Type instanceType = instance.GetType(); 
            object[] result = new object[2] { false, false };
 
            Type[] interfaces = instanceType.FindInterfaces(ModelTreeManager.CheckInterface, result);

            bool isList = (bool)result[0];
            bool isDictionary = (bool)result[1]; 

            if (isDictionary) 
            { 
                foreach (Type type in interfaces)
                { 
                    if (type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
                    {
                        // To expose one more property, a collection of MutableKeyValuePairs, to the model tree.
                        TypeDescriptor.AddProvider(new DictionaryTypeDescriptionProvider(instanceType), instance); 
                        break;
                    } 
                } 

                ModelItemDictionary modelItem = new ModelItemDictionaryImpl(this, instance.GetType(), instance, parent); 
                retval = modelItem;
            }
            else if (isList)
            { 
                ModelItemCollectionImpl modelItem = new ModelItemCollectionImpl(this, instance.GetType(), instance, parent);
                retval = modelItem; 
            } 
            else
            { 
                retval = new ModelItemImpl(this, instance.GetType(), instance, parent);
            }
            if (!((instance is ValueType) || (instance is string)))
            { 
                //
                // ValueType do not have a concept of shared reference, they are always copied. 
                // strings are immutatable, therefore the risk of making all shared string references to different 
                // string ModelItems is low.
                // 
                // To special case string is because underlying OM are sharing string objects for DisplayName across
                // Different activity object instances. These shared references is causing memory leak because of bugs.
                //
                // We will need to fix these issues in Beta2. 
                //
                objectMap[instance] = new WeakReference(retval); 
            } 

            if (this.FeatureManager != null) 
            {
                this.FeatureManager.InitializeFeature(instance.GetType());
            }
            return retval; 
        }
 
        static bool CheckInterface(Type type, object result) 
        {
            object[] values = (object[])result; 
            if (typeof(IList).IsAssignableFrom(type))
            {
                values[0] = true;
                return true; 
            }
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IList < > )) 
            { 
                values[0] = true;
                return true; 
            }
            if (typeof(IDictionary).IsAssignableFrom(type))
            {
                values[1] = true; 
                return true;
            } 
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary <, > )) 
            {
                values[1] = true; 
                return true;
            }
            return false;
        } 

        public void Load(object rootInstance) 
        { 
            if (rootInstance == null)
            { 
                throw FxTrace.Exception.AsError( new ArgumentNullException("rootInstance"));
            }
            objectMap.Clear();
 
            this.rootItem = WrapAsModelItem(null, rootInstance);
            if (this.modelService == null) 
            { 
                this.modelService = new ModelServiceImpl(this);
                this.context.Services.Publish(modelService); 
            }
        }

        // This methods clears the value of a property , if the property is 
        // a reference type then its set to null, if its a value type the
        // property value is reset to the default. this also clears the sub modelitem corresponding 
        // to the old value from the parent modelitem's modelPropertyStore. 
        internal void ClearValue(ModelPropertyImpl modelProperty)
        { 
            Fx.Assert(modelProperty != null, "modelProperty should not be null");
            Fx.Assert(modelProperty.Parent is IModelTreeItem, "modelProperty.Parent should be an IModelTreeItem");
            ModelItem newValueModelItem = null;
            newValueModelItem = WrapAsModelItem(null, modelProperty.DefaultValue); 
            PropertyChange propertyChange = new PropertyChange()
                { 
                    Owner = modelProperty.Parent, 
                    PropertyName = modelProperty.Name,
                    OldValue = modelProperty.Value, 
                    NewValue = newValueModelItem,
                    ModelTreeManager = this
                };
            AddToCurrentEditingScope(propertyChange); 
        }
 
        internal void CollectionAdd(ModelItemCollectionImpl dataModelItemCollection, ModelItem item) 
        {
            CollectionInsert(dataModelItemCollection, -1, item); 
        }

        internal void CollectionInsert(ModelItemCollectionImpl dataModelItemCollection, int index, ModelItem item)
        { 
            Fx.Assert(dataModelItemCollection != null,"collection should not be null");
            CollectionChange change = new CollectionChange() 
                { 
                    Collection = dataModelItemCollection,
                    Item = item, 
                    Index = index,
                    ModelTreeManager = this,
                    Operation = CollectionChange.OperationType.Insert
                }; 
            AddToCurrentEditingScope(change);
        } 
 
        internal void CollectionClear(ModelItemCollectionImpl modelItemCollectionImpl)
        { 
            Fx.Assert(modelItemCollectionImpl != null,"collection should not be null");
            Fx.Assert(this.modelService != null, "modelService should not be null");
            List removedItems = new List();
            removedItems.AddRange(modelItemCollectionImpl); 
            using (ModelEditingScope editingScope = CreateEditingScope(SR.CollectionClearEditingScopeDescription))
            { 
                foreach (ModelItem modelItem in removedItems) 
                {
                    this.CollectionRemove(modelItemCollectionImpl, modelItem); 
                }
                editingScope.Complete();
            }
            this.modelService.OnModelItemsRemoved(removedItems); 
        }
 
        internal void NotifyCollectionInsert(ModelItem item) 
        {
            this.modelService.OnModelItemAdded(item); 
        }

        internal void CollectionRemove(ModelItemCollectionImpl dataModelItemCollection, ModelItem item)
        { 
            CollectionRemove(dataModelItemCollection, item, -1);
        } 
 
        internal void CollectionRemoveAt(ModelItemCollectionImpl dataModelItemCollection, int index)
        { 
            ModelItem item = dataModelItemCollection[index];
            CollectionRemove(dataModelItemCollection, item, index);
        }
 
        void CollectionRemove(ModelItemCollectionImpl dataModelItemCollection, ModelItem item, int index)
        { 
            Fx.Assert(dataModelItemCollection != null,"collection should not be null"); 
            CollectionChange change = new CollectionChange()
                { 
                    Collection = dataModelItemCollection,
                    Item = item,
                    Index = index,
                    ModelTreeManager = this, 
                    Operation = CollectionChange.OperationType.Delete
                }; 
            AddToCurrentEditingScope(change); 
        }
 
        internal void NotifyCollectionRemove(ModelItem item)
        {
            this.modelService.OnModelItemRemoved(item);
        } 

        internal void DictionaryClear(ModelItemDictionaryImpl modelDictionary) 
        { 
            Fx.Assert(modelDictionary != null,"dictionary should not be null");
            Fx.Assert(this.modelService != null, "modelService should not be null"); 
            ModelItem[] keys = modelDictionary.Keys.ToArray();

            using (ModelEditingScope editingScope = CreateEditingScope(SR.DictionaryClearEditingScopeDescription))
            { 
                foreach (ModelItem key in keys)
                { 
                    this.DictionaryRemove(modelDictionary, key); 
                }
                editingScope.Complete(); 
            }
        }

        internal void DictionaryEdit(ModelItemDictionaryImpl dataModelItemDictionary, ModelItem key, ModelItem newValue, ModelItem oldValue) 
        {
            Fx.Assert(dataModelItemDictionary != null,"dictionary should not be null"); 
            Fx.Assert(this.modelService != null, "modelService should not be null"); 
            DictionaryEditChange change = new DictionaryEditChange()
                { 
                    Dictionary = dataModelItemDictionary,
                    Key = key,
                    NewValue = newValue,
                    OldValue = oldValue, 
                    ModelTreeManager = this
                }; 
            AddToCurrentEditingScope(change); 
        }
 
        internal void DictionaryAdd(ModelItemDictionaryImpl dataModelItemDictionary, ModelItem key, ModelItem value)
        {
            Fx.Assert(dataModelItemDictionary != null, "dictionary should not be null");
            Fx.Assert(this.modelService != null, "modelService should not be null"); 
            DictionaryChange change = new DictionaryChange()
                { 
                    Dictionary = dataModelItemDictionary, 
                    Key = key,
                    Value = value, 
                    Operation = DictionaryChange.OperationType.Insert,
                    ModelTreeManager = this
                };
            AddToCurrentEditingScope(change); 
        }
 
        internal void DictionaryRemove(ModelItemDictionaryImpl dataModelItemDictionary, ModelItem key) 
        {
            Fx.Assert(dataModelItemDictionary != null, "dictionary should not be null"); 
            Fx.Assert(this.modelService != null, "modelService should not be null");
            ModelItem value = dataModelItemDictionary[key];
            DictionaryChange change = new DictionaryChange()
                { 
                    Dictionary = dataModelItemDictionary,
                    Key = key, 
                    Value = value, 
                    Operation = DictionaryChange.OperationType.Delete,
                    ModelTreeManager = this 
                };
            AddToCurrentEditingScope(change);

        } 

        internal IEnumerable Find(ModelItem startingItem, Predicate matcher, bool skipCollapsedAndUnrootable) 
        { 
            Fx.Assert(startingItem != null, "starting item should not be null");
            Fx.Assert(matcher != null, "matching predicate should not be null"); 
            WorkflowViewService viewService = this.Context.Services.GetService() as WorkflowViewService;
            if (skipCollapsedAndUnrootable)
            {
                Fx.Assert(viewService != null, "ViewService must be available in order to skip exploring ModelItems whose views are collapsed."); 
            }
 
            List foundItems = new List(); 
            Queue modelItems = new Queue();
            modelItems.Enqueue(startingItem); 
            HashSet alreadyVisited = new HashSet();
            while (modelItems.Count > 0)
            {
                ModelItem currentModelItem = modelItems.Dequeue(); 
                if (currentModelItem == null)
                { 
                    continue; 
                }
 
                if (matcher(currentModelItem.ItemType))
                {
                    foundItems.Add(currentModelItem);
                } 

                ModelItemCollection collection = currentModelItem as ModelItemCollection; 
                if (collection != null) 
                {
                    foreach (ModelItem modelItem in collection) 
                    {
                        if (modelItem != null && !alreadyVisited.Contains(modelItem))
                        {
                            alreadyVisited.Add(modelItem); 
                            modelItems.Enqueue(modelItem);
                        } 
                    } 
                }
                else 
                {
                    ModelItemDictionary dictionary = currentModelItem as ModelItemDictionary;
                    if (dictionary != null)
                    { 
                        foreach (KeyValuePair kvp in dictionary)
                        { 
                            ModelItem miKey = kvp.Key; 
                            if (miKey != null && !alreadyVisited.Contains(miKey))
                            { 
                                alreadyVisited.Add(miKey);
                                modelItems.Enqueue(miKey);
                            }
 
                            ModelItem miValue = kvp.Value;
                            if (miValue != null && !alreadyVisited.Contains(miValue)) 
                            { 
                                alreadyVisited.Add(miValue);
                                modelItems.Enqueue(miValue); 
                            }
                        }
                    }
                } 

                if (!skipCollapsedAndUnrootable || !typeof(WorkflowViewElement).IsAssignableFrom(viewService.GetDesignerType(currentModelItem.ItemType)) || 
                    ViewUtilities.IsViewExpanded(currentModelItem, this.Context) && viewService.ShouldAppearOnBreadCrumb(currentModelItem, true)) 
                {
                    ModelPropertyCollection modelProperties = currentModelItem.Properties; 
                    foreach (ModelProperty property in modelProperties)
                    {
                        // we dont want to even try to get the value for a value type property
                        // because that will create a new modelitem everytime. 

                        // System.Type has properties that throw when we try to get value 
                        // we dont want to expand system.type further during a search. 
                        if (property.PropertyType.IsAssignableFrom(typeof(Type)) || property.PropertyType.IsValueType)
                        { 
                            continue;
                        }

                        else 
                        {
                            if (property.Value != null && !alreadyVisited.Contains(property.Value)) 
                            { 
                                alreadyVisited.Add(property.Value);
                                modelItems.Enqueue(property.Value); 
                            }
                        }
                    }
                } 
            }
            return foundItems; 
        } 

        internal ModelItem FindFirst(ModelItem startingItem, Predicate matcher) 
        {
            Fx.Assert(startingItem != null, "starting item should not be null");
            Fx.Assert(matcher != null, "matching predicate should not be null");
            ModelItem foundItem = null; 
            Queue modelItems = new Queue();
            modelItems.Enqueue(startingItem); 
            HashSet alreadyVisited = new HashSet(); 
            while (modelItems.Count > 0)
            { 
                ModelItem currentModelItem = modelItems.Dequeue();
                if (currentModelItem == null)
                {
                    continue; 
                }
 
                if (matcher(currentModelItem)) 
                {
                    foundItem = currentModelItem; 
                    break;
                }

                ModelItemCollection collection = currentModelItem as ModelItemCollection; 
                if (collection != null)
                { 
                    foreach (ModelItem modelItem in collection) 
                    {
                        if (modelItem != null && !alreadyVisited.Contains(modelItem)) 
                        {
                            alreadyVisited.Add(modelItem);
                            modelItems.Enqueue(modelItem);
                        } 
                    }
                } 
                else 
                {
                    ModelItemDictionary dictionary = currentModelItem as ModelItemDictionary; 
                    if (dictionary != null)
                    {
                        foreach (KeyValuePair kvp in dictionary)
                        { 
                            ModelItem miKey = kvp.Key;
                            if (miKey != null && !alreadyVisited.Contains(miKey)) 
                            { 
                                alreadyVisited.Add(miKey);
                                modelItems.Enqueue(miKey); 
                            }

                            ModelItem miValue = kvp.Value;
                            if (miValue != null && !alreadyVisited.Contains(miValue)) 
                            {
                                alreadyVisited.Add(miValue); 
                                modelItems.Enqueue(miValue); 
                            }
                        } 
                    }
                }

 
                ModelPropertyCollection modelProperties = currentModelItem.Properties;
                foreach (ModelProperty property in modelProperties) 
                { 
                    // we dont want to even try to get the value for a value type property
                    // because that will create a new modelitem everytime. 

                    // System.Type has properties that throw  when we try to get value
                    // we dont want to expand system.type further during a search.
                    if (property.PropertyType.IsAssignableFrom(typeof(Type)) || property.PropertyType.IsValueType) 
                    {
                        continue; 
                    } 

                    else 
                    {
                        if (property.Value != null && !alreadyVisited.Contains(property.Value))
                        {
                            alreadyVisited.Add(property.Value); 
                            modelItems.Enqueue(property.Value);
                        } 
                    } 
                }
            } 
            return foundItem;
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", 
          Justification = "If the property getter threw here we dont want to crash, we just dont want to wrap that property value")]
        [SuppressMessage("Reliability", "Reliability108:IsFatalRule", 
            Justification = "If the property getter threw here we dont want to crash, we just dont want to wrap that property value")] 
        internal ModelItem GetValue(ModelPropertyImpl dataModelProperty)
        { 
            Fx.Assert(dataModelProperty != null,"modelproperty should not be null");
            Fx.Assert(dataModelProperty.Parent is IModelTreeItem, "modelproperty.Parent should be an IModelTreeItem");
            IModelTreeItem parent = (IModelTreeItem)dataModelProperty.Parent;
            ModelItem value; 

            // always reevaluate attached properties. the cache in attached properties case is only to remember the old value. 
            if (!dataModelProperty.IsAttached && parent.ModelPropertyStore.ContainsKey(dataModelProperty.Name)) 
            {
                value = parent.ModelPropertyStore[dataModelProperty.Name]; 
            }
            // Create a ModelItem on demand for the value of the property.
            else
            { 
                try
                { 
                    value = WrapAsModelItem(null, dataModelProperty.PropertyDescriptor.GetValue(parent.ModelItem.GetCurrentValue())); 
                }
                catch (System.Exception) 
                {
                    // GetValue throws an exception if Value is not available
                    value = null;
                } 
                if (value != null)
                { 
                    if (!dataModelProperty.IsAttached) 
                    {
                        parent.ModelPropertyStore.Add(dataModelProperty.Name, value); 
                    }
                    ((IModelTreeItem)value).SetSource(dataModelProperty);
                }
            } 
            return value;
        } 
 
        internal ModelItem SetValue(ModelPropertyImpl modelProperty, object value)
        { 
            Fx.Assert(modelProperty != null, "modelProperty should not be null");
            ModelItem newValueModelItem = null;

            RefreshPropertiesAttribute refreshPropertiesAttribute = ExtensibilityAccessor.GetAttribute(modelProperty.Attributes); 
            if (refreshPropertiesAttribute != null && refreshPropertiesAttribute.RefreshProperties == RefreshProperties.All)
            { 
                ((IModelTreeItem)modelProperty.Parent).ModelPropertyStore.Clear(); 
            }
 
            if (value is ModelItem)
            {
                newValueModelItem = (ModelItem)value;
            } 
            else
            { 
                newValueModelItem = WrapAsModelItem(null, value); 
            }
            // dont do deferred updates for attached properties 
            if (modelProperty.IsAttached)
            {
                modelProperty.SetValueCore(newValueModelItem);
            } 
            else
            { 
                PropertyChange propertyChange = new PropertyChange() 
                {
                    Owner = modelProperty.Parent, 
                    PropertyName = modelProperty.Name,
                    OldValue = modelProperty.Value,
                    NewValue = newValueModelItem,
                    ModelTreeManager = this 
                };
                AddToCurrentEditingScope(propertyChange); 
            } 

 
            return newValueModelItem;
        }

 

        internal void AddToCurrentEditingScope(Change change) 
        { 
            EditingScope editingScope;
            if (editingScopes.Count > 0) 
            {
                editingScope = (EditingScope)editingScopes.Peek();
                // Automatic generated change during apply changes of Redo/Undo should be ignored.
                if (!RedoUndoInProgress) 
                {
                    editingScope.Changes.Add(change); 
                } 
            }
            else 
            {
                //edit operation without editingscope create an editing scope and complete it immediately.
                editingScope = CreateEditingScope(change.Description);
                editingScope.Changes.Add(change); 
                try
                { 
                    editingScope.Complete(); 
                }
                catch 
                {
                    editingScope.Revert();
                    throw;
                } 

            } 
 
        }
 
        internal EditingScope CreateEditingScope(string description)
        {
            EditingScope editingScope;
            EditingScope outerScope = editingScopes.Count > 0 ? (EditingScope)editingScopes.Peek() : null; 
            editingScope = new EditingScope(this, outerScope);
            editingScope.Description = description; 
            editingScopes.Push(editingScope); 
            return editingScope;
        } 

        internal void NotifyPropertyChange(ModelPropertyImpl dataModelProperty)
        {
            modelService.OnModelPropertyChanged(dataModelProperty); 
        }
 
 

 

        internal void SyncModelAndText()
        {
            // Place holder for xaml generation ModelTreeManager now is instance only. 
        }
 
        internal ModelItem WrapAsModelItem(ModelItem parent, object instance) 
        {
            ModelItem modelItem = GetModelItem(instance); 
            //first, check if model item exists - if it does, check if its parent needs to be set properly.
            if (instance != null && modelItem !=null)
            {
                if (null != parent) 
                {
                    ((IModelTreeItem)modelItem).SetParent(parent); 
                } 
            }
            //if one doesn't exists - create new one 
            else if (null != instance && null == modelItem)
            {
                modelItem = CreateModelItem(parent, instance);
            } 
            return modelItem;
        } 
 
        internal ModelItem GetModelItem(object instance)
        { 
            if (instance == null)
            {
                return null;
            } 
            ModelItem modelItem = null;
            WeakReference mappedModelItem = null; 
            objectMap.TryGetValue(instance, out mappedModelItem); 
            if (mappedModelItem != null)
            { 
                modelItem = (ModelItem)mappedModelItem.Target;
            }
            return modelItem;
        } 

        internal void ReAddModelItemToModelTree(ModelItem modelItem) 
        { 
            if (modelItem != null)
            { 
                IList modelItemsThatNeedBackLinkUpdate = ((IModelTreeItem)modelItem).SubNodesThatNeedBackLinkUpdate;
                if (modelItemsThatNeedBackLinkUpdate.Count > 0)
                {
                    foreach (ModelItem modelItemThatNeedsBackLinkUpdate in modelItemsThatNeedBackLinkUpdate) 
                    {
                        UpdateBackLinksForDependentsOf(modelItemThatNeedsBackLinkUpdate); 
                    } 
                    modelItemsThatNeedBackLinkUpdate.Clear();
                } 
            }
        }

        private void UpdateBackLinksForDependentsOf(ModelItem modelItem) 
        {
            //restore property backlinks 
 
            foreach (string propertyName in ((IModelTreeItem)modelItem).ModelPropertyStore.Keys)
            { 
                ModelItem propertyValueModelItem = ((IModelTreeItem)modelItem).ModelPropertyStore[propertyName];
                if(propertyValueModelItem != null)
                {
                    ((IModelTreeItem)propertyValueModelItem).SetSource(modelItem.Properties[propertyName]); 
                }
            } 
 
            // restore collection backlinks
 
            ModelItemCollection modelItemCollection = modelItem as ModelItemCollection;
            if (modelItemCollection != null)
            {
                foreach(ModelItem collectionChild in modelItemCollection) 
                {
                    if(collectionChild != null) 
                    { 
                        ((IModelTreeItem)collectionChild).SetParent(modelItemCollection);
                    } 
                }
            }

            // restore dictionary backlinks 

            ModelItemDictionary modelItemDictionary = modelItem as ModelItemDictionary; 
            if (modelItemDictionary != null) 
            {
                foreach (ModelItem keyModelItem in modelItemDictionary.Keys) 
                {
                    if (keyModelItem != null)
                    {
                        ((IModelTreeItem)keyModelItem).SetParent(modelItemDictionary); 
                    }
                } 
 
                foreach (ModelItem valueModelItem in modelItemDictionary.Values)
                { 
                    if (valueModelItem != null)
                    {
                        ((IModelTreeItem)valueModelItem).SetParent(modelItemDictionary);
                    } 
                }
            } 
 
        }
 
        internal void ReleaseModelItem(ModelItem oldValueModelItem, ModelItem parent)
        {
            Fx.Assert(oldValueModelItem != null, "old value modelItem should not be null");
            HashSet visited = new HashSet(); 
            Queue nodes = new Queue();
 
            nodes.Enqueue(new Dependency() { Parent = parent, Dependant = oldValueModelItem }); 
            while (nodes.Count > 0)
            { 
                Dependency dependency = nodes.Dequeue();
                if (HasNoOtherParents(dependency))
                {
                    // this node depends only on this parent, visit this. 
                    ModelItem currentModelItem = dependency.Dependant;
                    if (!visited.Contains(currentModelItem)) 
                    { 
                        visited.Add(currentModelItem);
                        foreach (ModelItem child in GetDependants(currentModelItem)) 
                        {
                            nodes.Enqueue(new Dependency() { Dependant = child, Parent = currentModelItem });
                        }
                    } 
                }
                else // This node has other references, dont dig any deeper, but remove its immediate backpointer to this parent. 
                { 
                    RemoveBackLink(dependency);
                    if (dependency.Dependant != oldValueModelItem) 
                    {
                        ((IModelTreeItem)oldValueModelItem).SubNodesThatNeedBackLinkUpdate.Add(dependency.Parent);
                    }
                } 
            }
 
 
        }
 
        private void RemoveBackLink(Dependency dependency)
        {
            // remove sources that have source.Parent == dependency.Parent
            var sourceBackLinks = from source in dependency.Dependant.Sources 
                where source.Parent == dependency.Parent
                select source; 
            foreach (ModelProperty sourceBackLink in sourceBackLinks.ToList()) 
            {
                ((IModelTreeItem)dependency.Dependant).RemoveSource(sourceBackLink); 
            }
            // remove collectionParents that equal dependency.Parent.
            ((IModelTreeItem)dependency.Dependant).RemoveParent(dependency.Parent);
        } 

 
        private IEnumerable GetDependants(ModelItem modelItem) 
        {
            List dependants = new List(); 

            // modelimpl- propertystore
            dependants.AddRange(((IModelTreeItem)modelItem).ModelPropertyStore.Values);
 
            // modelcolleciton - propertystore + items
            if (modelItem is ModelItemCollection) 
            { 
                dependants.AddRange((ModelItemCollection)modelItem);
            } 

                // modeldictionary - propertystore + keys + values;
            else if (modelItem is ModelItemDictionary)
            { 
                dependants.AddRange(((ModelItemDictionary)modelItem).Keys);
                dependants.AddRange(((ModelItemDictionary)modelItem).Values); 
            } 
            return dependants.Where(e => e != null);
        } 

        private bool HasNoOtherParents(Dependency dependency)
        {
            var otherParents = from parent in dependency.Dependant.Parents 
                where parent != dependency.Parent
                select parent; 
            return otherParents.Count() == 0; 
        }
 
        internal void OnEditingScopeCompleted(EditingScope modelEditingScopeImpl)
        {

            if (editingScopes.Contains(modelEditingScopeImpl)) 
            {
                editingScopes.Pop(); 
            } 
            // if the outer most scope completed notify listeners
            if (this.EditingScopeCompleted != null && editingScopes.Count == 0) 
            {
                this.EditingScopeCompleted(this, new EditingScopeEventArgs() { EditingScope = modelEditingScopeImpl });
            }
 
        }
 
        internal bool CanEditingScopeComplete(EditingScope modelEditingScopeImpl) 
        {
            ReadOnlyState readOnlyState = this.Context.Items.GetValue(); 
            return (modelEditingScopeImpl == editingScopes.Peek()) && (readOnlyState == null || !readOnlyState.IsReadOnly);
        }

        internal void OnEditingScopeReverted(EditingScope modelEditingScopeImpl) 
        {
            if (editingScopes.Contains(modelEditingScopeImpl)) 
            { 
                editingScopes.Pop();
            } 
        }

        class ObjectEqualityComparer : IEqualityComparer
        { 

            public int GetHashCode(object obj) 
            { 
                //If two reference objects are the same we return equal.
                //Object.GetHashCode() gurantees we return same hash code for same objects(equal references). 
                return obj.GetHashCode();
            }

            //We want to check reference equality for keys in ObjectMap. 
            //If the user overrides Equals method for their class we still want to use referential equality.
            public new bool Equals(object x, object y) 
            { 
                return object.ReferenceEquals(x, y);
            } 

        }

        class Dependency 
        {
            public ModelItem Parent { get; set; } 
            public ModelItem Dependant { get; set; } 
        }
 
        class DictionaryTypeDescriptionProvider : TypeDescriptionProvider
        {
            Type type;
            public DictionaryTypeDescriptionProvider(Type type) 
                : base(TypeDescriptor.GetProvider(type))
            { 
                this.type = type; 
            }
 
            public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
            {
                ICustomTypeDescriptor defaultDescriptor = base.GetTypeDescriptor(objectType, instance);
                return new DictionaryTypeDescriptor(defaultDescriptor, this.type); 
            }
        } 
 
        class DictionaryTypeDescriptor : CustomTypeDescriptor
        { 
            Type type;

            public DictionaryTypeDescriptor(ICustomTypeDescriptor parent, Type type)
                : base(parent) 
            {
                this.type = type; 
            } 

            // Expose one more property, a collection of MutableKeyValuePairs,  described by ItemsCollectionPropertyDescriptor 
            public override PropertyDescriptorCollection GetProperties()
            {
                return new PropertyDescriptorCollection(base.GetProperties().Cast()
                    .Union(new PropertyDescriptor[] {new ItemsCollectionPropertyDescriptor(type) }).ToArray()); 
            }
 
            // Expose one more property, a collection of MutableKeyValuePairs,  described by ItemsCollectionPropertyDescriptor 
            public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
            { 
                return new PropertyDescriptorCollection(base.GetProperties(attributes).Cast()
                    .Union(new PropertyDescriptor[] { new ItemsCollectionPropertyDescriptor(type) }).ToArray());
            }
        } 

        class ItemsCollectionPropertyDescriptor : PropertyDescriptor 
        { 
            Type dictionaryType;
            Type[] genericArguments; 
            Type kvpairType;
            Type itemType;
            Type propertyType;
 
            internal ItemsCollectionPropertyDescriptor(Type type)
                : base("ItemsCollection", null) 
            { 
                this.dictionaryType = type;
            } 

            Type[] GenericArguments
            {
                get 
                {
                    if (this.genericArguments == null) 
                    { 
                        object[] result = new object[2] { false, false };
                        Type[] interfaces = this.ComponentType.FindInterfaces(ModelTreeManager.CheckInterface, result); 
                        foreach (Type type in interfaces)
                        {
                            if (type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
                            { 
                                this.genericArguments = type.GetGenericArguments();
                                Fx.Assert(this.genericArguments.Length == 2, "this.genericArguments.Length should be = 2"); 
                                return this.genericArguments; 
                            }
                        } 
                        Debug.Fail("Cannot find generic arguments for IDictionary<,>.");
                    }
                    return this.genericArguments;
                } 
            }
 
            [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is intended for use through reflection")] 
            Type KVPairType
            { 
                get
                {
                    if (this.kvpairType == null)
                    { 
                        this.kvpairType = typeof(KeyValuePair<,>).MakeGenericType(this.GenericArguments);
                    } 
                    return this.kvpairType; 
                }
            } 

            [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is intended for use through reflection")]
            Type ItemType
            { 
                get
                { 
                    if (this.itemType == null) 
                    {
                        this.itemType = typeof(ModelItemKeyValuePair<,>).MakeGenericType(this.GenericArguments); 
                    }
                    return this.itemType;
                }
            } 

            public override Type ComponentType 
            { 
                get { return this.dictionaryType; }
            } 

            public override bool IsReadOnly
            {
                get 
                {
                    return true; 
                } 
            }
 
            public override Type PropertyType
            {
                get
                { 
                    if (this.propertyType == null)
                    { 
                        this.propertyType = typeof(DictionaryItemsCollection<,>).MakeGenericType(this.GenericArguments); 
                    }
                    return this.propertyType; 
                }
            }

            public override bool IsBrowsable 
            {
                get 
                { 
                    return false;
                } 
            }

            public override bool CanResetValue(object component)
            { 
                return false;
            } 
 
            public override object GetValue(object component)
            { 
                return Activator.CreateInstance(this.PropertyType, new object[] { component });
            }

            public override void ResetValue(object component) 
            {
                Debug.Fail("ResetValue is not implemented."); 
                throw FxTrace.Exception.AsError( new NotImplementedException()); 
            }
 
            public override void SetValue(object component, object value)
            {
                Debug.Fail("SetValue is not implemented.");
                throw FxTrace.Exception.AsError( new NotImplementedException()); 
            }
 
            public override bool ShouldSerializeValue(object component) 
            {
                return false; 
            }
        }
    }
} 

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