Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data / System / Data / DataViewListener.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="Select.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 //------------------------------------------------------------------------------
8
9 namespace System.Data {
10
11     using System;
12     using System.ComponentModel;
13     using System.Collections.Generic;
14     using System.Diagnostics;
15
16     internal sealed class DataViewListener {
17
18         private readonly WeakReference _dvWeak;
19         private DataTable _table;
20         private Index _index;
21
22         /// <summary><see cref="DataView.ObjectID"/></summary>
23         internal readonly int ObjectID;
24
25         internal DataViewListener(DataView dv) {
26             this.ObjectID = dv.ObjectID;
27             _dvWeak = new WeakReference(dv);
28         }
29
30         private void ChildRelationCollectionChanged(object sender, CollectionChangeEventArgs e) {
31             DataView dv = (DataView)_dvWeak.Target;
32             if (dv != null) {
33                 dv.ChildRelationCollectionChanged(sender, e);
34             }
35             else {
36                 CleanUp(true);
37             }
38         }
39
40         private void ParentRelationCollectionChanged(object sender, CollectionChangeEventArgs e) {
41             DataView dv = (DataView)_dvWeak.Target;
42             if (dv != null) {
43                 dv.ParentRelationCollectionChanged(sender, e);
44             }
45             else {
46                 CleanUp(true);
47             }
48         }
49
50         private void ColumnCollectionChanged(object sender, CollectionChangeEventArgs e) {
51             DataView dv = (DataView)_dvWeak.Target;
52             if (dv != null) {
53                 dv.ColumnCollectionChangedInternal(sender, e);
54             }
55             else {
56                 CleanUp(true);
57             }
58         }
59
60         /// <summary>
61         /// Maintain the DataView before <see cref="DataView.ListChanged"/> is raised.
62         /// </summary>
63         internal void MaintainDataView(ListChangedType changedType, DataRow row, bool trackAddRemove) {
64             DataView dv = (DataView)_dvWeak.Target;
65             if (dv != null) {
66                 dv.MaintainDataView(changedType, row, trackAddRemove);
67             }
68             else {
69                 CleanUp(true);
70             }
71         }
72
73         internal void IndexListChanged(ListChangedEventArgs e) {
74             DataView dv = (DataView)_dvWeak.Target;
75             if (dv != null) {
76                 dv.IndexListChangedInternal(e);
77             }
78             else {
79                 CleanUp(true);
80             }
81         }
82
83         internal void RegisterMetaDataEvents(DataTable table) {
84             Debug.Assert(null == _table, "DataViewListener already registered table");
85             _table = table;
86             if (table != null) {
87                 // actively remove listeners without a target
88                 RegisterListener(table);
89
90                 // start listening to events
91                 CollectionChangeEventHandler handlerCollection = new CollectionChangeEventHandler(ColumnCollectionChanged);
92                 table.Columns.ColumnPropertyChanged += handlerCollection;
93                 table.Columns.CollectionChanged += handlerCollection;
94
95                 CollectionChangeEventHandler handlerChildRelation = new CollectionChangeEventHandler(ChildRelationCollectionChanged);
96                 ((DataRelationCollection.DataTableRelationCollection)(table.ChildRelations)).RelationPropertyChanged += handlerChildRelation;
97                 table.ChildRelations.CollectionChanged += handlerChildRelation;
98
99                 CollectionChangeEventHandler handlerParentRelation = new CollectionChangeEventHandler(ParentRelationCollectionChanged);
100                 ((DataRelationCollection.DataTableRelationCollection)(table.ParentRelations)).RelationPropertyChanged += handlerParentRelation;
101                 table.ParentRelations.CollectionChanged += handlerParentRelation;
102             }
103         }
104
105         internal void UnregisterMetaDataEvents() {
106             UnregisterMetaDataEvents(true);
107         }
108
109         private void UnregisterMetaDataEvents(bool updateListeners) {
110             DataTable table = _table;
111             _table = null;
112
113             if (table != null) {
114                 CollectionChangeEventHandler handlerCollection = new CollectionChangeEventHandler(ColumnCollectionChanged);
115                 table.Columns.ColumnPropertyChanged -= handlerCollection;
116                 table.Columns.CollectionChanged -= handlerCollection;
117
118                 CollectionChangeEventHandler handlerChildRelation = new CollectionChangeEventHandler(ChildRelationCollectionChanged);
119                 ((DataRelationCollection.DataTableRelationCollection)(table.ChildRelations)).RelationPropertyChanged -= handlerChildRelation;
120                 table.ChildRelations.CollectionChanged -= handlerChildRelation;
121
122                 CollectionChangeEventHandler handlerParentRelation = new CollectionChangeEventHandler(ParentRelationCollectionChanged);
123                 ((DataRelationCollection.DataTableRelationCollection)(table.ParentRelations)).RelationPropertyChanged -= handlerParentRelation;
124                 table.ParentRelations.CollectionChanged -= handlerParentRelation;
125
126                 if (updateListeners) {
127                     List<DataViewListener> listeners = table.GetListeners();
128                     lock (listeners) {
129                         listeners.Remove(this);
130                     }
131                 }
132             }
133         }
134
135         internal void RegisterListChangedEvent(Index index) {
136             Debug.Assert(null == _index, "DataviewListener already registered index");
137             _index = index;
138             if (null != index) {
139                 lock (index) {
140                     index.AddRef();
141                     index.ListChangedAdd(this);
142                 }
143             }
144         }
145
146         internal void UnregisterListChangedEvent() {
147             Index index = _index;
148             _index = null;
149
150             if (index != null) {
151                 lock (index) {
152                     index.ListChangedRemove(this);
153                     if (index.RemoveRef() <= 1) {
154                         index.RemoveRef();
155                     }
156                 }
157             }
158         }
159
160         private void CleanUp(bool updateListeners) {
161             UnregisterMetaDataEvents(updateListeners);
162             UnregisterListChangedEvent();
163         }
164
165         private void RegisterListener(DataTable table) {
166             List<DataViewListener> listeners = table.GetListeners();
167             lock (listeners) {
168                 for (int i = listeners.Count - 1; 0 <= i; --i) {
169                     DataViewListener listener = listeners[i];
170                     if (!listener._dvWeak.IsAlive) {
171                         listeners.RemoveAt(i);
172                         listener.CleanUp(false);
173                     }
174                 }
175                 listeners.Add(this);
176             }
177         }
178     }
179 }