34c66fd490b57f603cf0a0c1803565ac9f9c6c1e
[mono.git] / mcs / class / referencesource / System / compmod / system / collections / specialized / notifycollectionchangedeventargs.cs
1 //---------------------------------------------------------------------------
2 //
3 // <copyright file="NotifyCollectionChangedEventArgs.cs" company="Microsoft">
4 //    Copyright (C) Microsoft Corporation.  All rights reserved.
5 // </copyright>
6 //
7 // Description: NotifyCollectionChanged event arguments
8 //
9 // Specs:       http://avalon/connecteddata/Specs/INotifyCollectionChanged.mht
10 //
11 //---------------------------------------------------------------------------
12
13 using System;
14 using System.Collections;
15 using System.Diagnostics.Contracts;
16 using System.Runtime.CompilerServices;
17
18 namespace System.Collections.Specialized
19 {
20     /// <summary>
21     /// This enum describes the action that caused a CollectionChanged event.
22     /// </summary>
23     [TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
24     public enum NotifyCollectionChangedAction
25     {
26         /// <summary> One or more items were added to the collection. </summary>
27         Add,
28         /// <summary> One or more items were removed from the collection. </summary>
29         Remove,
30         /// <summary> One or more items were replaced in the collection. </summary>
31         Replace,
32         /// <summary> One or more items were moved within the collection. </summary>
33         Move,
34         /// <summary> The contents of the collection changed dramatically. </summary>
35         Reset,
36     }
37
38     /// <summary>
39     /// Arguments for the CollectionChanged event.
40     /// A collection that supports INotifyCollectionChangedThis raises this event
41     /// whenever an item is added or removed, or when the contents of the collection
42     /// changes dramatically.
43     /// </summary>
44     [TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
45     public class NotifyCollectionChangedEventArgs : EventArgs
46     {
47         //------------------------------------------------------
48         //
49         //  Constructors
50         //
51         //------------------------------------------------------
52
53         /// <summary>
54         /// Construct a NotifyCollectionChangedEventArgs that describes a reset change.
55         /// </summary>
56         /// <param name="action">The action that caused the event (must be Reset).</param>
57         public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action)
58         {
59             if (action != NotifyCollectionChangedAction.Reset)
60                 throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Reset), "action");
61
62             InitializeAdd(action, null, -1);
63         }
64
65         /// <summary>
66         /// Construct a NotifyCollectionChangedEventArgs that describes a one-item change.
67         /// </summary>
68         /// <param name="action">The action that caused the event; can only be Reset, Add or Remove action.</param>
69         /// <param name="changedItem">The item affected by the change.</param>
70         public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem)
71         {
72             if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
73                     && (action != NotifyCollectionChangedAction.Reset))
74                 throw new ArgumentException(SR.GetString(SR.MustBeResetAddOrRemoveActionForCtor), "action");
75
76             if (action == NotifyCollectionChangedAction.Reset)
77             {
78                 if (changedItem != null)
79                     throw new ArgumentException(SR.GetString(SR.ResetActionRequiresNullItem), "action");
80
81                 InitializeAdd(action, null, -1);
82             }
83             else
84             {
85                 InitializeAddOrRemove(action, new object[]{changedItem}, -1);
86             }
87         }
88
89         /// <summary>
90         /// Construct a NotifyCollectionChangedEventArgs that describes a one-item change.
91         /// </summary>
92         /// <param name="action">The action that caused the event.</param>
93         /// <param name="changedItem">The item affected by the change.</param>
94         /// <param name="index">The index where the change occurred.</param>
95         public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index)
96         {
97             if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
98                     && (action != NotifyCollectionChangedAction.Reset))
99                 throw new ArgumentException(SR.GetString(SR.MustBeResetAddOrRemoveActionForCtor), "action");
100
101             if (action == NotifyCollectionChangedAction.Reset)
102             {
103                 if (changedItem != null)
104                     throw new ArgumentException(SR.GetString(SR.ResetActionRequiresNullItem), "action");
105                 if (index != -1)
106                     throw new ArgumentException(SR.GetString(SR.ResetActionRequiresIndexMinus1), "action");
107
108                 InitializeAdd(action, null, -1);
109             }
110             else
111             {
112                 InitializeAddOrRemove(action, new object[]{changedItem}, index);
113             }
114         }
115
116         /// <summary>
117         /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item change.
118         /// </summary>
119         /// <param name="action">The action that caused the event.</param>
120         /// <param name="changedItems">The items affected by the change.</param>
121         public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems)
122         {
123             if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
124                     && (action != NotifyCollectionChangedAction.Reset))
125                 throw new ArgumentException(SR.GetString(SR.MustBeResetAddOrRemoveActionForCtor), "action");
126
127             if (action == NotifyCollectionChangedAction.Reset)
128             {
129                 if (changedItems != null)
130                     throw new ArgumentException(SR.GetString(SR.ResetActionRequiresNullItem), "action");
131
132                 InitializeAdd(action, null, -1);
133             }
134             else
135             {
136                 if (changedItems == null)
137                     throw new ArgumentNullException("changedItems");
138
139                 InitializeAddOrRemove(action, changedItems, -1);
140             }
141         }
142
143         /// <summary>
144         /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item change (or a reset).
145         /// </summary>
146         /// <param name="action">The action that caused the event.</param>
147         /// <param name="changedItems">The items affected by the change.</param>
148         /// <param name="startingIndex">The index where the change occurred.</param>
149         public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
150         {
151             if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
152                     && (action != NotifyCollectionChangedAction.Reset))
153                 throw new ArgumentException(SR.GetString(SR.MustBeResetAddOrRemoveActionForCtor), "action");
154
155             if (action == NotifyCollectionChangedAction.Reset)
156             {
157                 if (changedItems != null)
158                     throw new ArgumentException(SR.GetString(SR.ResetActionRequiresNullItem), "action");
159                 if (startingIndex != -1)
160                     throw new ArgumentException(SR.GetString(SR.ResetActionRequiresIndexMinus1), "action");
161
162                 InitializeAdd(action, null, -1);
163             }
164             else
165             {
166                 if (changedItems == null)
167                     throw new ArgumentNullException("changedItems");
168                 if (startingIndex < -1)
169                     throw new ArgumentException(SR.GetString(SR.IndexCannotBeNegative), "startingIndex");
170
171                 InitializeAddOrRemove(action, changedItems, startingIndex);
172             }
173         }
174
175         /// <summary>
176         /// Construct a NotifyCollectionChangedEventArgs that describes a one-item Replace event.
177         /// </summary>
178         /// <param name="action">Can only be a Replace action.</param>
179         /// <param name="newItem">The new item replacing the original item.</param>
180         /// <param name="oldItem">The original item that is replaced.</param>
181         public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem)
182         {
183             if (action != NotifyCollectionChangedAction.Replace)
184                 throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Replace), "action");
185
186             InitializeMoveOrReplace(action, new object[]{newItem}, new object[]{oldItem}, -1, -1);
187         }
188
189         /// <summary>
190         /// Construct a NotifyCollectionChangedEventArgs that describes a one-item Replace event.
191         /// </summary>
192         /// <param name="action">Can only be a Replace action.</param>
193         /// <param name="newItem">The new item replacing the original item.</param>
194         /// <param name="oldItem">The original item that is replaced.</param>
195         /// <param name="index">The index of the item being replaced.</param>
196         public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem, int index)
197         {
198             if (action != NotifyCollectionChangedAction.Replace)
199                 throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Replace), "action");
200
201             int oldStartingIndex = index;
202
203 #if FEATURE_LEGACYNETCF
204             if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
205             {
206                 // Dev11 444113 quirk:
207                 // This is a "Replace" so the old and new index should both be set to the index passed in however
208                 // NetCF on Mango incorrectly leaves OldStartingIndex at -1 and Mango apps depend on this behavior.
209                 oldStartingIndex = -1;
210             }
211 #endif
212             InitializeMoveOrReplace(action, new object[]{newItem}, new object[]{oldItem}, index, oldStartingIndex);
213         }
214
215         /// <summary>
216         /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Replace event.
217         /// </summary>
218         /// <param name="action">Can only be a Replace action.</param>
219         /// <param name="newItems">The new items replacing the original items.</param>
220         /// <param name="oldItems">The original items that are replaced.</param>
221         public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems)
222         {
223             if (action != NotifyCollectionChangedAction.Replace)
224                 throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Replace), "action");
225             if (newItems == null)
226                 throw new ArgumentNullException("newItems");
227             if (oldItems == null)
228                 throw new ArgumentNullException("oldItems");
229
230             InitializeMoveOrReplace(action, newItems, oldItems, -1, -1);
231         }
232
233         /// <summary>
234         /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Replace event.
235         /// </summary>
236         /// <param name="action">Can only be a Replace action.</param>
237         /// <param name="newItems">The new items replacing the original items.</param>
238         /// <param name="oldItems">The original items that are replaced.</param>
239         /// <param name="startingIndex">The starting index of the items being replaced.</param>
240         public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex)
241         {
242             if (action != NotifyCollectionChangedAction.Replace)
243                 throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Replace), "action");
244             if (newItems == null)
245                 throw new ArgumentNullException("newItems");
246             if (oldItems == null)
247                 throw new ArgumentNullException("oldItems");
248
249             InitializeMoveOrReplace(action, newItems, oldItems, startingIndex, startingIndex);
250         }
251
252         /// <summary>
253         /// Construct a NotifyCollectionChangedEventArgs that describes a one-item Move event.
254         /// </summary>
255         /// <param name="action">Can only be a Move action.</param>
256         /// <param name="changedItem">The item affected by the change.</param>
257         /// <param name="index">The new index for the changed item.</param>
258         /// <param name="oldIndex">The old index for the changed item.</param>
259         public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index, int oldIndex)
260         {
261             if (action != NotifyCollectionChangedAction.Move)
262                 throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Move), "action");
263             if (index < 0)
264                 throw new ArgumentException(SR.GetString(SR.IndexCannotBeNegative), "index");
265
266             object[] changedItems= new object[] {changedItem};
267             InitializeMoveOrReplace(action, changedItems, changedItems, index, oldIndex);
268         }
269
270         /// <summary>
271         /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Move event.
272         /// </summary>
273         /// <param name="action">The action that caused the event.</param>
274         /// <param name="changedItems">The items affected by the change.</param>
275         /// <param name="index">The new index for the changed items.</param>
276         /// <param name="oldIndex">The old index for the changed items.</param>
277         public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int index, int oldIndex)
278         {
279             if (action != NotifyCollectionChangedAction.Move)
280                 throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Move), "action");
281             if (index < 0)
282                 throw new ArgumentException(SR.GetString(SR.IndexCannotBeNegative), "index");
283
284             InitializeMoveOrReplace(action, changedItems, changedItems, index, oldIndex);
285         }
286
287         /// <summary>
288         /// Construct a NotifyCollectionChangedEventArgs with given fields (no validation). Used by WinRT marshaling.
289         /// </summary>
290         internal NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int newIndex, int oldIndex)
291         {
292             _action = action;
293 #if FEATURE_LEGACYNETCF
294             if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
295             {
296                 _newItems = newItems;
297             }
298             else
299 #endif
300             {
301                 _newItems = (newItems == null) ? null : ArrayList.ReadOnly(newItems);
302             }
303             _oldItems = (oldItems == null) ? null : ArrayList.ReadOnly(oldItems);
304             _newStartingIndex = newIndex;
305             _oldStartingIndex = oldIndex;
306         }
307
308         private void InitializeAddOrRemove(NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
309         {
310             if (action == NotifyCollectionChangedAction.Add)
311                 InitializeAdd(action, changedItems, startingIndex);
312             else if (action == NotifyCollectionChangedAction.Remove)
313                 InitializeRemove(action, changedItems, startingIndex);
314             else
315                 Contract.Assert(false, String.Format("Unsupported action: {0}", action.ToString()));
316         }
317
318         private void InitializeAdd(NotifyCollectionChangedAction action, IList newItems, int newStartingIndex)
319         {
320             _action = action;
321 #if FEATURE_LEGACYNETCF
322             if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
323             {
324                 _newItems = newItems;
325             }
326             else
327 #endif // !FEATURE_LEGACYNETCF
328             {
329                 _newItems = (newItems == null) ? null : ArrayList.ReadOnly(newItems);
330             }
331             _newStartingIndex = newStartingIndex;
332         }
333
334         private void InitializeRemove(NotifyCollectionChangedAction action, IList oldItems, int oldStartingIndex)
335         {
336             _action = action;
337             _oldItems = (oldItems == null) ? null : ArrayList.ReadOnly(oldItems);
338             _oldStartingIndex= oldStartingIndex;
339         }
340
341         private void InitializeMoveOrReplace(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex, int oldStartingIndex)
342         {
343             InitializeAdd(action, newItems, startingIndex);
344             InitializeRemove(action, oldItems, oldStartingIndex);
345         }
346
347         //------------------------------------------------------
348         //
349         //  Public Properties
350         //
351         //------------------------------------------------------
352
353         /// <summary>
354         /// The action that caused the event.
355         /// </summary>
356         public NotifyCollectionChangedAction Action
357         {
358             get { return _action; }
359         }
360
361         /// <summary>
362         /// The items affected by the change.
363         /// </summary>
364         public IList NewItems
365         {
366             get { return _newItems; }
367         }
368
369         /// <summary>
370         /// The old items affected by the change (for Replace events).
371         /// </summary>
372         public IList OldItems
373         {
374             get { return _oldItems; }
375         }
376
377         /// <summary>
378         /// The index where the change occurred.
379         /// </summary>
380         public int NewStartingIndex
381         {
382             get { return _newStartingIndex; }
383         }
384
385         /// <summary>
386         /// The old index where the change occurred (for Move events).
387         /// </summary>
388         public int OldStartingIndex
389         {
390             get { return _oldStartingIndex; }
391         }
392
393         //------------------------------------------------------
394         //
395         //  Private Fields
396         //
397         //------------------------------------------------------
398
399         private NotifyCollectionChangedAction _action;
400         private IList _newItems, _oldItems;
401         private int _newStartingIndex = -1;
402         private int _oldStartingIndex = -1;
403     }
404
405     /// <summary>
406     ///     The delegate to use for handlers that receive the CollectionChanged event.
407     /// </summary>
408     [TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
409     public delegate void NotifyCollectionChangedEventHandler(object sender, NotifyCollectionChangedEventArgs e);
410
411 }
412
413