[runtime] Fix corlib out of date error with disabled COM
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / View / TreeView / ChangeNotificationTracker.cs
1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------
4
5 namespace System.Activities.Presentation.View.TreeView
6 {
7     using System;
8     using System.Activities.Presentation.Model;
9     using System.Collections.Generic;
10     using System.Collections.Specialized;
11
12     class ChangeNotificationTracker
13     {
14         private bool? delayUpdates = null;
15
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; }
20
21         public TreeViewItemViewModel Parent { get; private set; }
22
23         // Guard to delay processing events while handling another event
24         private bool? DelayUpdates
25         {
26             get
27             {
28                 return this.delayUpdates;
29             }
30
31             set
32             {
33                 bool? oldDelayUpdates = this.delayUpdates;
34                 this.delayUpdates = value;
35
36                 // If necessary, perform delayed updates when initial handling completes
37                 if (null == this.delayUpdates && null != oldDelayUpdates && (bool)oldDelayUpdates)
38                 {
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);
43                 }
44             }
45         }
46
47         /// <summary>
48         /// Is the tracked node still existed in the outline tree.
49         /// </summary>
50         private bool IsTrackedNodeAlive
51         {
52             get
53             {
54                 return this.Parent.IsAlive;
55             }
56         }
57
58         //prevent creating ChangeNotificationTracker without parent
59         private ChangeNotificationTracker()
60         {
61         }
62
63         public ChangeNotificationTracker(TreeViewItemViewModel parent, ModelProperty parentProperty)
64         {
65             if (parent == null)
66             {
67                 throw FxTrace.Exception.AsError(new ArgumentNullException("parent"));
68             }
69             if (parentProperty == null)
70             {
71                 throw FxTrace.Exception.AsError(new ArgumentNullException("parentProperty"));
72             }
73             this.Parent = parent;
74             this.ParentProperty = parentProperty;
75             this.TrackedModelItem = new Dictionary<ModelItem, HashSet<string>>();
76             this.TrackedCollection = new List<INotifyCollectionChanged>();
77             this.ChildViewModels = new List<TreeViewItemViewModel>();
78         }
79
80         public void Add(ModelItem modelItem, ModelProperty property)
81         {
82             this.Add(modelItem, property.Name);
83         }
84
85         public void Add(ModelItem modelItem, string propertyName)
86         {
87             HashSet<string> propertyList = null;
88             if (!TrackedModelItem.TryGetValue(modelItem, out propertyList))
89             {
90                 modelItem.PropertyChanged += new ComponentModel.PropertyChangedEventHandler(modelItem_PropertyChanged);
91                 propertyList = new HashSet<string>();
92                 TrackedModelItem.Add(modelItem, propertyList);
93             }
94             propertyList.Add(propertyName);
95         }
96
97         public void AddCollection(INotifyCollectionChanged collection)
98         {
99             this.TrackedCollection.Add(collection);
100             collection.CollectionChanged += new Collections.Specialized.NotifyCollectionChangedEventHandler(collection_CollectionChanged);
101         }
102
103         void collection_CollectionChanged(object sender, Collections.Specialized.NotifyCollectionChangedEventArgs e)
104         {
105             if (!IsTrackedNodeAlive)
106             {
107                 return;
108             }
109
110             this.UpdateChildren(e);
111         }
112
113         public void CleanUp()
114         {
115             foreach (ModelItem modelItem in TrackedModelItem.Keys)
116             {
117                 modelItem.PropertyChanged -= new ComponentModel.PropertyChangedEventHandler(modelItem_PropertyChanged);
118             }
119             TrackedModelItem.Clear();
120             foreach (INotifyCollectionChanged collection in TrackedCollection)
121             {
122                 collection.CollectionChanged -= new Collections.Specialized.NotifyCollectionChangedEventHandler(collection_CollectionChanged);
123             }
124             TrackedCollection.Clear();
125             //remove childViewModels
126             foreach (TreeViewItemViewModel child in ChildViewModels)
127             {
128                 this.Parent.InternalChildren.Remove(child);
129                 child.CleanUp();
130             }
131             this.ChildViewModels.Clear();
132         }
133
134         void modelItem_PropertyChanged(object sender, ComponentModel.PropertyChangedEventArgs e)
135         {
136             if (!IsTrackedNodeAlive)
137             {
138                 return;
139             }
140
141             ModelItem modelItem = sender as ModelItem;
142             if (modelItem != null)
143             {
144                 HashSet<string> propertyList = null;
145                 if (TrackedModelItem.TryGetValue(modelItem, out propertyList))
146                 {
147                     if (propertyList.Contains(e.PropertyName))
148                     {
149                         this.UpdateChildren(e);
150                     }
151                 }
152             }
153         }
154
155         void UpdateChildren(EventArgs e)
156         {
157             if (null == this.DelayUpdates)
158             {
159                 this.DelayUpdates = false;
160                 this.Parent.UpdateChildren(this, e);
161                 this.DelayUpdates = null;
162             }
163             else
164             {
165                 // Called while handling another event for this tracker
166                 this.DelayUpdates = true;
167             }
168         }
169     }
170 }