1
+ using System ;
2
+ using System . Collections ;
3
+ using System . Collections . Generic ;
4
+ using System . Collections . ObjectModel ;
5
+ using System . Linq ;
6
+ using Microsoft . UI . Xaml . Data ;
7
+ using Microsoft . UI . Xaml . Interop ;
8
+
9
+ namespace Microsoft . Toolkit . Graph . Controls
10
+ {
11
+ // .NET collection types are tightly coupled with WUX types - e.g., ObservableCollection<T>
12
+ // maps to WUX.INotifyCollectionChanged, and creates WUX.NotifyCollectionChangedEventArgs
13
+ // when raising its INCC event. This is a problem because we've switched everything else over
14
+ // to use MUX types, such that creating WUX types raises an RPC_E_WRONG_THREAD error
15
+ // due to DXamlCore not being initialized. For the purposes of our tests, we're providing
16
+ // our own implementation of TestObservableCollection<T> that implements MUX.INotifyCollectionChanged.
17
+ #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
18
+ public class TestObservableCollection < T > : Collection < T > , Microsoft . UI . Xaml . Interop . INotifyCollectionChanged , INotifyPropertyChanged
19
+ {
20
+ private ReentrancyGuard reentrancyGuard = null ;
21
+
22
+ private class ReentrancyGuard : IDisposable
23
+ {
24
+ private TestObservableCollection < T > owningCollection ;
25
+
26
+ public ReentrancyGuard ( TestObservableCollection < T > owningCollection )
27
+ {
28
+ owningCollection . CheckReentrancy ( ) ;
29
+ owningCollection . reentrancyGuard = this ;
30
+ this . owningCollection = owningCollection ;
31
+ }
32
+
33
+ public void Dispose ( )
34
+ {
35
+ owningCollection . reentrancyGuard = null ;
36
+ }
37
+ }
38
+
39
+ public TestObservableCollection ( )
40
+ : base ( )
41
+ {
42
+ }
43
+
44
+ public TestObservableCollection ( IList < T > list )
45
+ : base ( list . ToList ( ) )
46
+ {
47
+ }
48
+
49
+ public TestObservableCollection ( IEnumerable < T > collection )
50
+ : base ( collection . ToList ( ) )
51
+ {
52
+ }
53
+
54
+ public event NotifyCollectionChangedEventHandler CollectionChanged ;
55
+
56
+ public void Move ( int oldIndex , int newIndex )
57
+ {
58
+ MoveItem ( oldIndex , newIndex ) ;
59
+ }
60
+
61
+ protected IDisposable BlockReentrancy ( )
62
+ {
63
+ return new ReentrancyGuard ( this ) ;
64
+ }
65
+
66
+ protected void CheckReentrancy ( )
67
+ {
68
+ if ( reentrancyGuard != null )
69
+ {
70
+ throw new InvalidOperationException ( "Collection cannot be modified in a collection changed handler." ) ;
71
+ }
72
+ }
73
+
74
+ protected override void ClearItems ( )
75
+ {
76
+ CheckReentrancy ( ) ;
77
+
78
+ TestBindableVector < T > oldItems = new TestBindableVector < T > ( this ) ;
79
+
80
+ base . ClearItems ( ) ;
81
+ OnCollectionChanged (
82
+ global ::System . Collections . Specialized . NotifyCollectionChangedAction . Reset ,
83
+ null ,
84
+ oldItems ,
85
+ 0 ,
86
+ 0 ) ;
87
+ }
88
+
89
+ protected override void InsertItem ( int index , T item )
90
+ {
91
+ CheckReentrancy ( ) ;
92
+
93
+ TestBindableVector < T > newItem = new TestBindableVector < T > ( ) ;
94
+ newItem . Add ( item ) ;
95
+
96
+ base . InsertItem ( index , item ) ;
97
+ OnCollectionChanged (
98
+ global ::System . Collections . Specialized . NotifyCollectionChangedAction . Add ,
99
+ newItem ,
100
+ null ,
101
+ index ,
102
+ 0 ) ;
103
+ }
104
+
105
+ protected virtual void MoveItem ( int oldIndex , int newIndex )
106
+ {
107
+ CheckReentrancy ( ) ;
108
+
109
+ TestBindableVector < T > oldItem = new TestBindableVector < T > ( ) ;
110
+ oldItem . Add ( this [ oldIndex ] ) ;
111
+ TestBindableVector < T > newItem = new TestBindableVector < T > ( oldItem ) ;
112
+
113
+ T item = this [ oldIndex ] ;
114
+ base . RemoveAt ( oldIndex ) ;
115
+ base . InsertItem ( newIndex , item ) ;
116
+ OnCollectionChanged (
117
+ global ::System . Collections . Specialized . NotifyCollectionChangedAction . Move ,
118
+ newItem ,
119
+ oldItem ,
120
+ newIndex ,
121
+ oldIndex ) ;
122
+ }
123
+
124
+ protected override void RemoveItem ( int index )
125
+ {
126
+ CheckReentrancy ( ) ;
127
+
128
+ TestBindableVector < T > oldItem = new TestBindableVector < T > ( ) ;
129
+ oldItem . Add ( this [ index ] ) ;
130
+
131
+ base . RemoveItem ( index ) ;
132
+ OnCollectionChanged (
133
+ global ::System . Collections . Specialized . NotifyCollectionChangedAction . Remove ,
134
+ null ,
135
+ oldItem ,
136
+ 0 ,
137
+ index ) ;
138
+ }
139
+
140
+ protected override void SetItem ( int index , T item )
141
+ {
142
+ CheckReentrancy ( ) ;
143
+
144
+ TestBindableVector < T > oldItem = new TestBindableVector < T > ( ) ;
145
+ oldItem . Add ( this [ index ] ) ;
146
+ TestBindableVector < T > newItem = new TestBindableVector < T > ( ) ;
147
+ newItem . Add ( item ) ;
148
+
149
+ base . SetItem ( index , item ) ;
150
+ OnCollectionChanged (
151
+ global ::System . Collections . Specialized . NotifyCollectionChangedAction . Replace ,
152
+ newItem ,
153
+ oldItem ,
154
+ index ,
155
+ index ) ;
156
+ }
157
+
158
+ protected virtual void OnCollectionChanged (
159
+ global ::System . Collections . Specialized . NotifyCollectionChangedAction action ,
160
+ IBindableVector newItems ,
161
+ IBindableVector oldItems ,
162
+ int newIndex ,
163
+ int oldIndex )
164
+ {
165
+ OnCollectionChanged ( new NotifyCollectionChangedEventArgs ( action , newItems , oldItems , newIndex , oldIndex ) ) ;
166
+ }
167
+
168
+ protected virtual void OnCollectionChanged ( NotifyCollectionChangedEventArgs e )
169
+ {
170
+ using ( BlockReentrancy ( ) )
171
+ {
172
+ CollectionChanged ? . Invoke ( this , e ) ;
173
+ }
174
+ }
175
+
176
+ public event PropertyChangedEventHandler PropertyChanged ;
177
+ }
178
+
179
+ #pragma warning disable SA1402 // File may only contain a single class
180
+ public class TestBindableVector < T > : IList < T > , IBindableVector
181
+ #pragma warning restore SA1402 // File may only contain a single class
182
+ {
183
+ private IList < T > implementation ;
184
+
185
+ public TestBindableVector ( )
186
+ {
187
+ implementation = new List < T > ( ) ;
188
+ }
189
+
190
+ public TestBindableVector ( IList < T > list )
191
+ {
192
+ implementation = new List < T > ( list ) ;
193
+ }
194
+
195
+ public T this [ int index ] { get => implementation [ index ] ; set => implementation [ index ] = value ; }
196
+
197
+ public int Count => implementation . Count ;
198
+
199
+ public virtual bool IsReadOnly => implementation . IsReadOnly ;
200
+
201
+ public void Add ( T item )
202
+ {
203
+ implementation . Add ( item ) ;
204
+ }
205
+
206
+ public void Clear ( )
207
+ {
208
+ implementation . Clear ( ) ;
209
+ }
210
+
211
+ public bool Contains ( T item )
212
+ {
213
+ return implementation . Contains ( item ) ;
214
+ }
215
+
216
+ public void CopyTo ( T [ ] array , int arrayIndex )
217
+ {
218
+ implementation . CopyTo ( array , arrayIndex ) ;
219
+ }
220
+
221
+ public IEnumerator < T > GetEnumerator ( )
222
+ {
223
+ return implementation . GetEnumerator ( ) ;
224
+ }
225
+
226
+ public int IndexOf ( T item )
227
+ {
228
+ return implementation . IndexOf ( item ) ;
229
+ }
230
+
231
+ public void Insert ( int index , T item )
232
+ {
233
+ implementation . Insert ( index , item ) ;
234
+ }
235
+
236
+ public bool Remove ( T item )
237
+ {
238
+ return implementation . Remove ( item ) ;
239
+ }
240
+
241
+ public void RemoveAt ( int index )
242
+ {
243
+ implementation . RemoveAt ( index ) ;
244
+ }
245
+
246
+ IEnumerator IEnumerable . GetEnumerator ( )
247
+ {
248
+ return implementation . GetEnumerator ( ) ;
249
+ }
250
+
251
+ public object GetAt ( uint index )
252
+ {
253
+ return implementation [ ( int ) index ] ;
254
+ }
255
+
256
+ public IBindableVectorView GetView ( )
257
+ {
258
+ return new TestBindableVectorView < T > ( implementation ) ;
259
+ }
260
+
261
+ public bool IndexOf ( object value , out uint index )
262
+ {
263
+ int indexOf = implementation . IndexOf ( ( T ) value ) ;
264
+
265
+ if ( indexOf >= 0 )
266
+ {
267
+ index = ( uint ) indexOf ;
268
+ return true ;
269
+ }
270
+ else
271
+ {
272
+ index = 0 ;
273
+ return false ;
274
+ }
275
+ }
276
+
277
+ public void SetAt ( uint index , object value )
278
+ {
279
+ implementation [ ( int ) index ] = ( T ) value ;
280
+ }
281
+
282
+ public void InsertAt ( uint index , object value )
283
+ {
284
+ implementation . Insert ( ( int ) index , ( T ) value ) ;
285
+ }
286
+
287
+ public void RemoveAt ( uint index )
288
+ {
289
+ implementation . RemoveAt ( ( int ) index ) ;
290
+ }
291
+
292
+ public void Append ( object value )
293
+ {
294
+ implementation . Add ( ( T ) value ) ;
295
+ }
296
+
297
+ public void RemoveAtEnd ( )
298
+ {
299
+ implementation . RemoveAt ( implementation . Count - 1 ) ;
300
+ }
301
+
302
+ public uint Size => ( uint ) implementation . Count ;
303
+
304
+ public IBindableIterator First ( )
305
+ {
306
+ return new TestBindableIterator < T > ( implementation ) ;
307
+ }
308
+ }
309
+
310
+ #pragma warning disable SA1402 // File may only contain a single class
311
+ public class TestBindableVectorView < T > : TestBindableVector < T > , IBindableVectorView
312
+ #pragma warning restore SA1402 // File may only contain a single class
313
+ {
314
+ public TestBindableVectorView ( IList < T > list )
315
+ : base ( list )
316
+ {
317
+ }
318
+
319
+ public override bool IsReadOnly => true ;
320
+ }
321
+
322
+ #pragma warning disable SA1402 // File may only contain a single class
323
+ public class TestBindableIterator < T > : IBindableIterator
324
+ #pragma warning restore SA1402 // File may only contain a single class
325
+ {
326
+ private readonly IEnumerator < T > enumerator ;
327
+
328
+ public TestBindableIterator ( IEnumerable < T > enumerable )
329
+ {
330
+ enumerator = enumerable . GetEnumerator ( ) ;
331
+ }
332
+
333
+ public bool MoveNext ( )
334
+ {
335
+ return enumerator . MoveNext ( ) ;
336
+ }
337
+
338
+ public object Current => enumerator . Current ;
339
+
340
+ public bool HasCurrent => enumerator . Current != null ;
341
+ }
342
+ #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
343
+ }
0 commit comments