1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //-----------------------------------------------------------------------------
5 namespace System.Activities.Presentation.Model
7 using System.Activities.Presentation.Services;
8 using System.Activities.Presentation.View;
9 using System.Collections.Generic;
10 using System.Collections.ObjectModel;
11 using System.ComponentModel;
12 using System.Diagnostics;
15 using System.Reflection;
18 using System.Windows.Markup;
22 // This class provides the View facing ModelItem implementation, this works with the ModelTreeManager
23 // and keeps the xaml up to date by intercepting every change to the model properties.
25 class ModelItemImpl : ModelItem, IModelTreeItem, ICustomTypeDescriptor, IDynamicMetaObjectProvider
27 ModelProperty contentProperty;
30 Dictionary<string, ModelItem> modelPropertyStore;
31 ModelTreeManager modelTreeManager;
32 ModelProperty nameProperty;
33 internal ObservableCollection<ModelItem> parents;
34 ReadOnlyObservableCollection<ModelItem> internalParents;
35 ModelPropertyCollectionImpl properties;
36 ObservableCollection<ModelProperty> sources;
37 ModelTreeItemHelper helper;
38 ReadOnlyObservableCollection<ModelProperty> internalSources;
39 List<ModelItem> subTreeNodesThatNeedBackLinkPatching;
40 DependencyObject view;
41 ModelItem manuallySetParent;
44 public ModelItemImpl(ModelTreeManager modelTreeManager, Type itemType, object instance, ModelItem parent)
46 this.itemType = itemType;
47 this.instance = instance;
48 this.modelTreeManager = modelTreeManager;
49 this.parents = new ObservableCollection<ModelItem>();
50 this.internalParents = new ReadOnlyObservableCollection<ModelItem>(parents);
51 this.sources = new ObservableCollection<ModelProperty>();
52 this.helper = new ModelTreeItemHelper();
53 this.internalSources = new ReadOnlyObservableCollection<ModelProperty>(sources);
56 this.manuallySetParent = parent;
58 this.modelPropertyStore = new Dictionary<string, ModelItem>();
59 this.subTreeNodesThatNeedBackLinkPatching = new List<ModelItem>();
64 public override event PropertyChangedEventHandler PropertyChanged;
66 public override global::System.ComponentModel.AttributeCollection Attributes
70 return TypeDescriptor.GetAttributes(itemType);
74 public override ModelProperty Content
79 if (this.contentProperty == null)
81 Fx.Assert(this.instance != null, "instance should not be null");
83 ContentPropertyAttribute contentAttribute = TypeDescriptor.GetAttributes(this.instance)[typeof(ContentPropertyAttribute)] as ContentPropertyAttribute;
84 if (contentAttribute != null && !String.IsNullOrEmpty(contentAttribute.Name))
86 this.contentProperty = this.Properties.Find(contentAttribute.Name);
89 return contentProperty;
93 public override Type ItemType
101 public ModelItem ModelItem
109 public override string Name
114 if ((this.NameProperty != null) && (this.NameProperty.Value != null))
116 name = (string)this.NameProperty.Value.GetCurrentValue();
122 if (this.NameProperty != null)
124 this.NameProperty.SetValue(value);
129 public override ModelItem Parent
133 return (this.Parents.Count() > 0) ? this.Parents.First() : null;
138 public override ModelPropertyCollection Properties
142 if (this.properties == null)
144 properties = new ModelPropertyCollectionImpl(this);
150 public override ModelItem Root
154 return this.modelTreeManager.Root;
159 // This holds a reference to the modelproperty that is currently holding this ModelItem.
160 public override ModelProperty Source
164 return (this.sources.Count > 0) ? this.sources.First() : null;
168 public override DependencyObject View
176 public override IEnumerable<ModelItem> Parents
180 if (this.manuallySetParent != null)
182 List<ModelItem> list = new List<ModelItem>();
183 list.Add(this.manuallySetParent);
184 return list.Concat(this.parents).Concat(
185 from source in this.sources
186 select source.Parent);
189 return this.parents.Concat(
190 from source in this.sources
191 select source.Parent);
195 internal ReadOnlyObservableCollection<ModelItem> InternalParents
199 return internalParents;
203 public override IEnumerable<ModelProperty> Sources
211 internal ReadOnlyObservableCollection<ModelProperty> InternalSources
215 return internalSources;
219 protected ModelProperty NameProperty
223 if (this.nameProperty == null)
225 Fx.Assert(this.instance != null, "instance should not be null");
227 RuntimeNamePropertyAttribute runtimeNamePropertyAttribute = TypeDescriptor.GetAttributes(this.instance)[typeof(RuntimeNamePropertyAttribute)] as RuntimeNamePropertyAttribute;
228 if (runtimeNamePropertyAttribute != null && !String.IsNullOrEmpty(runtimeNamePropertyAttribute.Name))
230 this.nameProperty = this.Properties.Find(runtimeNamePropertyAttribute.Name);
238 Dictionary<string, ModelItem> IModelTreeItem.ModelPropertyStore
242 return modelPropertyStore;
246 ModelTreeManager IModelTreeItem.ModelTreeManager
250 return modelTreeManager;
254 void IModelTreeItem.SetCurrentView(DependencyObject view)
259 public override ModelEditingScope BeginEdit(string description, bool shouldApplyChangesImmediately)
261 return ModelItemHelper.ModelItemBeginEdit(this.modelTreeManager, description, shouldApplyChangesImmediately);
264 public override ModelEditingScope BeginEdit(bool shouldApplyChangesImmediately)
266 return this.BeginEdit(null, shouldApplyChangesImmediately);
269 public override ModelEditingScope BeginEdit(string description)
271 return this.BeginEdit(description, false);
274 public override ModelEditingScope BeginEdit()
276 return this.BeginEdit(null);
279 public override object GetCurrentValue()
281 return this.instance;
284 void IModelTreeItem.OnPropertyChanged(string propertyName)
286 this.OnPropertyChanged(propertyName);
290 void IModelTreeItem.SetParent(ModelItem dataModelItem)
292 if (this.manuallySetParent == dataModelItem)
294 this.manuallySetParent = null;
297 if (dataModelItem != null && !this.parents.Contains(dataModelItem))
299 this.parents.Add(dataModelItem);
303 IEnumerable<ModelItem> IModelTreeItem.ItemBackPointers
305 get { return this.parents; }
308 List<BackPointer> IModelTreeItem.ExtraPropertyBackPointers
310 get { return this.helper.ExtraPropertyBackPointers; }
313 void IModelTreeItem.SetSource(ModelProperty property)
315 if (!this.sources.Contains(property))
317 // also check if the same parent.property is in the list as a different instance of oldModelProperty
318 ModelProperty foundProperty = sources.FirstOrDefault<ModelProperty>((modelProperty) =>
319 modelProperty.Name.Equals(property.Name) && property.Parent == modelProperty.Parent);
320 if (foundProperty == null)
322 this.sources.Add(property);
327 #region ICustomTypeDescriptor Members
329 AttributeCollection ICustomTypeDescriptor.GetAttributes()
331 return this.Attributes;
334 string ICustomTypeDescriptor.GetClassName()
336 return TypeDescriptor.GetClassName(this);
339 string ICustomTypeDescriptor.GetComponentName()
341 return TypeDescriptor.GetComponentName(this);
344 TypeConverter ICustomTypeDescriptor.GetConverter()
346 return ModelUtilities.GetConverter(this);
349 EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
351 // we dont support events;
355 PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
357 return ModelUtilities.GetDefaultProperty(this);
360 object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
362 // we dont support editors
366 EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
368 // we dont support events;
372 EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
374 // we dont support events;
378 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
380 return ModelUtilities.WrapProperties(this);
383 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
385 // get model properties
386 List<PropertyDescriptor> properties = new List<PropertyDescriptor>();
389 foreach (PropertyDescriptor modelPropertyDescriptor in ModelUtilities.WrapProperties(this))
391 properties.Add(modelPropertyDescriptor);
394 // try to see if there are pseudo builtin properties for this type.
395 AttachedPropertiesService AttachedPropertiesService = this.modelTreeManager.Context.Services.GetService<AttachedPropertiesService>();
396 if (AttachedPropertiesService != null)
398 var nonBrowsableAttachedProperties = from attachedProperty in AttachedPropertiesService.GetAttachedProperties(this.itemType)
399 where (!attachedProperty.IsBrowsable && !attachedProperty.IsVisibleToModelItem)
400 select attachedProperty;
402 foreach (AttachedProperty AttachedProperty in nonBrowsableAttachedProperties)
404 properties.Add(new AttachedPropertyDescriptor(AttachedProperty, this));
407 return new PropertyDescriptorCollection(properties.ToArray(), true);
410 object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
418 void IModelTreeItem.RemoveParent(ModelItem oldParent)
420 if (this.manuallySetParent == oldParent)
422 this.manuallySetParent = null;
425 if (this.parents.Contains(oldParent))
427 this.parents.Remove(oldParent);
431 void IModelTreeItem.RemoveSource(ModelProperty oldModelProperty)
433 if (this.sources.Contains(oldModelProperty))
435 this.sources.Remove(oldModelProperty);
439 ((IModelTreeItem)this).RemoveSource(oldModelProperty.Parent, oldModelProperty.Name);
443 void IModelTreeItem.RemoveSource(ModelItem parent, string propertyName)
445 // also check if the same parent.property is in the list as a different instance of oldModelProperty
446 ModelProperty foundProperty = this.sources.FirstOrDefault<ModelProperty>((modelProperty) => modelProperty.Name.Equals(propertyName) && modelProperty.Parent == parent);
447 if (foundProperty != null)
449 this.sources.Remove(foundProperty);
453 this.helper.RemoveExtraPropertyBackPointer(parent, propertyName);
457 protected virtual void OnPropertyChanged(string propertyName)
459 if (PropertyChanged != null)
461 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
465 DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(System.Linq.Expressions.Expression parameter)
467 return new ModelItemMetaObject(parameter, this);
470 public object SetPropertyValue(string propertyName, object val)
472 ModelProperty modelProperty = this.Properties.Find(propertyName);
473 if (modelProperty != null)
475 modelProperty.SetValue(val);
479 PropertyDescriptor descriptor = TypeDescriptor.GetProperties(this)[propertyName];
480 if (descriptor != null)
482 descriptor.SetValue(this, val);
485 return GetPropertyValue(propertyName);
488 public object GetPropertyValue(string propertyName)
490 ModelProperty modelProperty = this.Properties.Find(propertyName);
492 if (modelProperty != null)
494 ModelItem valueModelitem = modelProperty.Value;
495 if (valueModelitem == null)
501 Type itemType = valueModelitem.ItemType;
502 if (itemType.IsPrimitive || itemType.IsEnum || itemType.Equals(typeof(String)))
504 value = valueModelitem.GetCurrentValue();
508 value = valueModelitem;
515 PropertyDescriptor descriptor = TypeDescriptor.GetProperties(this)[propertyName];
516 if (descriptor != null)
518 value = descriptor.GetValue(this);
524 class ModelItemMetaObject : System.Dynamic.DynamicMetaObject
526 MethodInfo getPropertyValueMethodInfo = typeof(ModelItemImpl).GetMethod("GetPropertyValue");
527 MethodInfo setPropertyValueMethodInfo = typeof(ModelItemImpl).GetMethod("SetPropertyValue");
529 public ModelItemMetaObject(System.Linq.Expressions.Expression parameter, ModelItemImpl target)
530 : base(parameter, BindingRestrictions.Empty, target)
534 public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
536 System.Linq.Expressions.Expression s = System.Linq.Expressions.Expression.Convert(this.Expression, typeof(ModelItemImpl));
537 System.Linq.Expressions.Expression value = System.Linq.Expressions.Expression.Call(s, getPropertyValueMethodInfo, System.Linq.Expressions.Expression.Constant(binder.Name));
538 return new DynamicMetaObject(value, BindingRestrictions.GetTypeRestriction(this.Expression, this.LimitType));
541 public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
543 System.Linq.Expressions.Expression s = System.Linq.Expressions.Expression.Convert(this.Expression, typeof(ModelItemImpl));
544 System.Linq.Expressions.Expression objectValue = System.Linq.Expressions.Expression.Convert(value.Expression, typeof(object));
545 System.Linq.Expressions.Expression valueExp = System.Linq.Expressions.Expression.Call(s, setPropertyValueMethodInfo, System.Linq.Expressions.Expression.Constant(binder.Name), objectValue);
546 return new DynamicMetaObject(valueExp, BindingRestrictions.GetTypeRestriction(this.Expression, this.LimitType));