1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------
5 namespace System.Activities.Presentation.View.TreeView
8 using System.Activities.Presentation.Model;
9 using System.Collections.Generic;
10 using System.Collections.Specialized;
12 class ChangeNotificationTracker
14 private bool? delayUpdates = null;
16 public ModelProperty ParentProperty { get; set; }
17 public Dictionary<ModelItem, HashSet<string>> TrackedModelItem { get; set; }
18 public List<INotifyCollectionChanged> TrackedCollection { get; set; }
19 public List<TreeViewItemViewModel> ChildViewModels { get; set; }
21 public TreeViewItemViewModel Parent { get; private set; }
23 // Guard to delay processing events while handling another event
24 private bool? DelayUpdates
28 return this.delayUpdates;
33 bool? oldDelayUpdates = this.delayUpdates;
34 this.delayUpdates = value;
36 // If necessary, perform delayed updates when initial handling completes
37 if (null == this.delayUpdates && null != oldDelayUpdates && (bool)oldDelayUpdates)
39 // We do not preserve args of events that occurred within a handler
40 // Fortunately EventArgs parameter to UpdateChildren() is presently unused
41 // Pass null to fast-fail if this parameter is used in the future
42 this.Parent.UpdateChildren(this, null);
48 /// Is the tracked node still existed in the outline tree.
50 private bool IsTrackedNodeAlive
54 return this.Parent.IsAlive;
58 //prevent creating ChangeNotificationTracker without parent
59 private ChangeNotificationTracker()
63 public ChangeNotificationTracker(TreeViewItemViewModel parent, ModelProperty parentProperty)
67 throw FxTrace.Exception.AsError(new ArgumentNullException("parent"));
69 if (parentProperty == null)
71 throw FxTrace.Exception.AsError(new ArgumentNullException("parentProperty"));
74 this.ParentProperty = parentProperty;
75 this.TrackedModelItem = new Dictionary<ModelItem, HashSet<string>>();
76 this.TrackedCollection = new List<INotifyCollectionChanged>();
77 this.ChildViewModels = new List<TreeViewItemViewModel>();
80 public void Add(ModelItem modelItem, ModelProperty property)
82 this.Add(modelItem, property.Name);
85 public void Add(ModelItem modelItem, string propertyName)
87 HashSet<string> propertyList = null;
88 if (!TrackedModelItem.TryGetValue(modelItem, out propertyList))
90 modelItem.PropertyChanged += new ComponentModel.PropertyChangedEventHandler(modelItem_PropertyChanged);
91 propertyList = new HashSet<string>();
92 TrackedModelItem.Add(modelItem, propertyList);
94 propertyList.Add(propertyName);
97 public void AddCollection(INotifyCollectionChanged collection)
99 this.TrackedCollection.Add(collection);
100 collection.CollectionChanged += new Collections.Specialized.NotifyCollectionChangedEventHandler(collection_CollectionChanged);
103 void collection_CollectionChanged(object sender, Collections.Specialized.NotifyCollectionChangedEventArgs e)
105 if (!IsTrackedNodeAlive)
110 this.UpdateChildren(e);
113 public void CleanUp()
115 foreach (ModelItem modelItem in TrackedModelItem.Keys)
117 modelItem.PropertyChanged -= new ComponentModel.PropertyChangedEventHandler(modelItem_PropertyChanged);
119 TrackedModelItem.Clear();
120 foreach (INotifyCollectionChanged collection in TrackedCollection)
122 collection.CollectionChanged -= new Collections.Specialized.NotifyCollectionChangedEventHandler(collection_CollectionChanged);
124 TrackedCollection.Clear();
125 //remove childViewModels
126 foreach (TreeViewItemViewModel child in ChildViewModels)
128 this.Parent.InternalChildren.Remove(child);
131 this.ChildViewModels.Clear();
134 void modelItem_PropertyChanged(object sender, ComponentModel.PropertyChangedEventArgs e)
136 if (!IsTrackedNodeAlive)
141 ModelItem modelItem = sender as ModelItem;
142 if (modelItem != null)
144 HashSet<string> propertyList = null;
145 if (TrackedModelItem.TryGetValue(modelItem, out propertyList))
147 if (propertyList.Contains(e.PropertyName))
149 this.UpdateChildren(e);
155 void UpdateChildren(EventArgs e)
157 if (null == this.DelayUpdates)
159 this.DelayUpdates = false;
160 this.Parent.UpdateChildren(this, e);
161 this.DelayUpdates = null;
165 // Called while handling another event for this tracker
166 this.DelayUpdates = true;