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