├── ICommand.cs
├── ICommand.cs.meta
├── INotifyCollectionChanged.cs
├── INotifyCollectionChanged.cs.meta
├── NotifyCollectionChangedEventArgs.cs
├── NotifyCollectionChangedEventArgs.cs.meta
├── ObservableCollection.cs
├── ObservableCollection.cs.meta
└── README.md
/ICommand.cs:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // Copyright (C) Microsoft Corporation. All rights reserved.
4 | //
5 | //---------------------------------------------------------------------------
6 |
7 | // Adapted for Unity
8 |
9 | #if !NETFX_CORE
10 |
11 | namespace System.Windows.Input
12 | {
13 | ///
14 | /// An interface that allows an application author to define a method to be invoked.
15 | ///
16 | public interface ICommand
17 | {
18 | ///
19 | /// Raised when the ability of the command to execute has changed.
20 | ///
21 | event EventHandler CanExecuteChanged;
22 |
23 | ///
24 | /// Returns whether the command can be executed.
25 | ///
26 | /// A parameter that may be used in executing the command. This parameter may be ignored by some implementations.
27 | /// true if the command can be executed with the given parameter and current state. false otherwise.
28 | bool CanExecute(object parameter);
29 |
30 | ///
31 | /// Defines the method that should be executed when the command is executed.
32 | ///
33 | /// A parameter that may be used in executing the command. This parameter may be ignored by some implementations.
34 | void Execute(object parameter);
35 | }
36 | }
37 |
38 | #endif
--------------------------------------------------------------------------------
/ICommand.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 286c9c0f4dda27b4f8940957677e6ec0
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/INotifyCollectionChanged.cs:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | //
4 | // Copyright (C) 2003 by Microsoft Corporation. All rights reserved.
5 | //
6 | //
7 | //
8 | // Description: Allows collections to notify listeners of dynamic updates.
9 | //
10 | // See spec at http://avalon/connecteddata/Specs/INotifyCollectionChanged.mht
11 | //
12 | //---------------------------------------------------------------------------
13 |
14 | // Adapted for Unity
15 |
16 | #if !NETFX_CORE
17 |
18 | namespace System.Collections.Specialized
19 | {
20 | ///
21 | /// A collection implementing this interface will notify listeners of dynamic changes,
22 | /// e.g. when items get added and removed or the whole list is refreshed.
23 | ///
24 | public interface INotifyCollectionChanged
25 | {
26 | ///
27 | /// Occurs when the collection changes, either by adding or removing an item.
28 | ///
29 | ///
30 | /// The event handler receives an argument of type
31 | ///
32 | /// containing data related to this event.
33 | ///
34 | event NotifyCollectionChangedEventHandler CollectionChanged;
35 | }
36 | }
37 |
38 | #endif
--------------------------------------------------------------------------------
/INotifyCollectionChanged.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 12a97e7948c8d4342925e0635dcac469
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/NotifyCollectionChangedEventArgs.cs:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | //
4 | // Copyright (C) Microsoft Corporation. All rights reserved.
5 | //
6 | //
7 | // Description: NotifyCollectionChanged event arguments
8 | //
9 | // Specs: http://avalon/connecteddata/Specs/INotifyCollectionChanged.mht
10 | //
11 | //---------------------------------------------------------------------------
12 |
13 | // Adapted for Unity
14 |
15 | #if !NETFX_CORE
16 |
17 | namespace System.Collections.Specialized
18 | {
19 | ///
20 | /// This enum describes the action that caused a CollectionChanged event.
21 | ///
22 | public enum NotifyCollectionChangedAction
23 | {
24 | /// One or more items were added to the collection.
25 | Add,
26 |
27 | /// One or more items were removed from the collection.
28 | Remove,
29 |
30 | /// One or more items were replaced in the collection.
31 | Replace,
32 |
33 | /// One or more items were moved within the collection.
34 | Move,
35 |
36 | /// The contents of the collection changed dramatically.
37 | Reset,
38 | }
39 |
40 | ///
41 | /// Arguments for the CollectionChanged event.
42 | /// A collection that supports INotifyCollectionChangedThis raises this event
43 | /// whenever an item is added or removed, or when the contents of the collection
44 | /// changes dramatically.
45 | ///
46 | public class NotifyCollectionChangedEventArgs : EventArgs
47 | {
48 | //------------------------------------------------------
49 | //
50 | // Constructors
51 | //
52 | //------------------------------------------------------
53 |
54 | ///
55 | /// Construct a NotifyCollectionChangedEventArgs that describes a reset change.
56 | ///
57 | /// The action that caused the event (must be Reset).
58 | public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action)
59 | {
60 | if (action != NotifyCollectionChangedAction.Reset)
61 | throw new ArgumentException("This constructor can only be used with the Reset action.", "action");
62 |
63 | InitializeAdd(action, null, -1);
64 | }
65 |
66 | ///
67 | /// Construct a NotifyCollectionChangedEventArgs that describes a one-item change.
68 | ///
69 | /// The action that caused the event; can only be Reset, Add or Remove action.
70 | /// The item affected by the change.
71 | public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem)
72 | {
73 | if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
74 | && (action != NotifyCollectionChangedAction.Reset))
75 | throw new ArgumentException("This constructor can only be used with the Reset, Add, or Remove actions.", "action");
76 |
77 | if (action == NotifyCollectionChangedAction.Reset)
78 | {
79 | if (changedItem != null)
80 | throw new ArgumentException("This constructor can only be used with the Reset action if changedItem is null", "action");
81 |
82 | InitializeAdd(action, null, -1);
83 | }
84 | else
85 | {
86 | InitializeAddOrRemove(action, new object[] { changedItem }, -1);
87 | }
88 | }
89 |
90 | ///
91 | /// Construct a NotifyCollectionChangedEventArgs that describes a one-item change.
92 | ///
93 | /// The action that caused the event.
94 | /// The item affected by the change.
95 | /// The index where the change occurred.
96 | public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index)
97 | {
98 | if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
99 | && (action != NotifyCollectionChangedAction.Reset))
100 | throw new ArgumentException("This constructor can only be used with the Reset, Add, or Remove actions.", "action");
101 |
102 | if (action == NotifyCollectionChangedAction.Reset)
103 | {
104 | if (changedItem != null)
105 | throw new ArgumentException("This constructor can only be used with the Reset action if changedItem is null", "action");
106 | if (index != -1)
107 | throw new ArgumentException("This constructor can only be used with the Reset action if index is -1", "action");
108 |
109 | InitializeAdd(action, null, -1);
110 | }
111 | else
112 | {
113 | InitializeAddOrRemove(action, new object[] { changedItem }, index);
114 | }
115 | }
116 |
117 | ///
118 | /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item change.
119 | ///
120 | /// The action that caused the event.
121 | /// The items affected by the change.
122 | public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems)
123 | {
124 | if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
125 | && (action != NotifyCollectionChangedAction.Reset))
126 | throw new ArgumentException("This constructor can only be used with the Reset, Add, or Remove actions.", "action");
127 |
128 | if (action == NotifyCollectionChangedAction.Reset)
129 | {
130 | if (changedItems != null)
131 | throw new ArgumentException("This constructor can only be used with the Reset action if changedItem is null", "action");
132 |
133 | InitializeAdd(action, null, -1);
134 | }
135 | else
136 | {
137 | if (changedItems == null)
138 | throw new ArgumentNullException("changedItems");
139 |
140 | InitializeAddOrRemove(action, changedItems, -1);
141 | }
142 | }
143 |
144 | ///
145 | /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item change (or a reset).
146 | ///
147 | /// The action that caused the event.
148 | /// The items affected by the change.
149 | /// The index where the change occurred.
150 | public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
151 | {
152 | if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
153 | && (action != NotifyCollectionChangedAction.Reset))
154 | throw new ArgumentException("This constructor can only be used with the Reset, Add, or Remove actions.", "action");
155 |
156 | if (action == NotifyCollectionChangedAction.Reset)
157 | {
158 | if (changedItems != null)
159 | throw new ArgumentException("This constructor can only be used with the Reset action if changedItem is null", "action");
160 | if (startingIndex != -1)
161 | throw new ArgumentException("This constructor can only be used with the Reset action if index is -1", "action");
162 |
163 | InitializeAdd(action, null, -1);
164 | }
165 | else
166 | {
167 | if (changedItems == null)
168 | throw new ArgumentNullException("changedItems");
169 | if (startingIndex < -1)
170 | throw new ArgumentException("The value of index must be -1 or greater.", "startingIndex");
171 |
172 | InitializeAddOrRemove(action, changedItems, startingIndex);
173 | }
174 | }
175 |
176 | ///
177 | /// Construct a NotifyCollectionChangedEventArgs that describes a one-item Replace event.
178 | ///
179 | /// Can only be a Replace action.
180 | /// The new item replacing the original item.
181 | /// The original item that is replaced.
182 | public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem)
183 | {
184 | if (action != NotifyCollectionChangedAction.Replace)
185 | throw new ArgumentException("This constructor can only be used with the Replace action.", "action");
186 |
187 | InitializeMoveOrReplace(action, new object[] { newItem }, new object[] { oldItem }, -1, -1);
188 | }
189 |
190 | ///
191 | /// Construct a NotifyCollectionChangedEventArgs that describes a one-item Replace event.
192 | ///
193 | /// Can only be a Replace action.
194 | /// The new item replacing the original item.
195 | /// The original item that is replaced.
196 | /// The index of the item being replaced.
197 | public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem, int index)
198 | {
199 | if (action != NotifyCollectionChangedAction.Replace)
200 | throw new ArgumentException("This constructor can only be used with the Replace action.", "action");
201 |
202 | int oldStartingIndex = index;
203 |
204 | InitializeMoveOrReplace(action, new object[] { newItem }, new object[] { oldItem }, index, oldStartingIndex);
205 | }
206 |
207 | ///
208 | /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Replace event.
209 | ///
210 | /// Can only be a Replace action.
211 | /// The new items replacing the original items.
212 | /// The original items that are replaced.
213 | public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems)
214 | {
215 | if (action != NotifyCollectionChangedAction.Replace)
216 | throw new ArgumentException("This constructor can only be used with the Replace action.", "action");
217 | if (newItems == null)
218 | throw new ArgumentNullException("newItems");
219 | if (oldItems == null)
220 | throw new ArgumentNullException("oldItems");
221 |
222 | InitializeMoveOrReplace(action, newItems, oldItems, -1, -1);
223 | }
224 |
225 | ///
226 | /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Replace event.
227 | ///
228 | /// Can only be a Replace action.
229 | /// The new items replacing the original items.
230 | /// The original items that are replaced.
231 | /// The starting index of the items being replaced.
232 | public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex)
233 | {
234 | if (action != NotifyCollectionChangedAction.Replace)
235 | throw new ArgumentException("This constructor can only be used with the Replace action.", "action");
236 | if (newItems == null)
237 | throw new ArgumentNullException("newItems");
238 | if (oldItems == null)
239 | throw new ArgumentNullException("oldItems");
240 |
241 | InitializeMoveOrReplace(action, newItems, oldItems, startingIndex, startingIndex);
242 | }
243 |
244 | ///
245 | /// Construct a NotifyCollectionChangedEventArgs that describes a one-item Move event.
246 | ///
247 | /// Can only be a Move action.
248 | /// The item affected by the change.
249 | /// The new index for the changed item.
250 | /// The old index for the changed item.
251 | public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index, int oldIndex)
252 | {
253 | if (action != NotifyCollectionChangedAction.Move)
254 | throw new ArgumentException("This constructor can only be used with the Move action.", "action");
255 | if (index < 0)
256 | throw new ArgumentException("The value of index must be -1 or greater.", "index");
257 |
258 | object[] changedItems = new object[] { changedItem };
259 | InitializeMoveOrReplace(action, changedItems, changedItems, index, oldIndex);
260 | }
261 |
262 | ///
263 | /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Move event.
264 | ///
265 | /// The action that caused the event.
266 | /// The items affected by the change.
267 | /// The new index for the changed items.
268 | /// The old index for the changed items.
269 | public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int index, int oldIndex)
270 | {
271 | if (action != NotifyCollectionChangedAction.Move)
272 | throw new ArgumentException("This constructor can only be used with the Move action.", "action");
273 | if (index < 0)
274 | throw new ArgumentException("The value of index must be -1 or greater.", "index");
275 |
276 | InitializeMoveOrReplace(action, changedItems, changedItems, index, oldIndex);
277 | }
278 |
279 | ///
280 | /// Construct a NotifyCollectionChangedEventArgs with given fields (no validation). Used by WinRT marshaling.
281 | ///
282 | internal NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int newIndex, int oldIndex)
283 | {
284 | _action = action;
285 | _newItems = (newItems == null) ? null : ArrayList.ReadOnly(newItems);
286 | _oldItems = (oldItems == null) ? null : ArrayList.ReadOnly(oldItems);
287 | _newStartingIndex = newIndex;
288 | _oldStartingIndex = oldIndex;
289 | }
290 |
291 | private void InitializeAddOrRemove(NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
292 | {
293 | if (action == NotifyCollectionChangedAction.Add)
294 | InitializeAdd(action, changedItems, startingIndex);
295 | else if (action == NotifyCollectionChangedAction.Remove)
296 | InitializeRemove(action, changedItems, startingIndex);
297 | else
298 | throw new ArgumentException("This method must be used with the Add or Remove action.", "action");
299 | }
300 |
301 | private void InitializeAdd(NotifyCollectionChangedAction action, IList newItems, int newStartingIndex)
302 | {
303 | _action = action;
304 | _newItems = (newItems == null) ? null : ArrayList.ReadOnly(newItems);
305 | _newStartingIndex = newStartingIndex;
306 | }
307 |
308 | private void InitializeRemove(NotifyCollectionChangedAction action, IList oldItems, int oldStartingIndex)
309 | {
310 | _action = action;
311 | _oldItems = (oldItems == null) ? null : ArrayList.ReadOnly(oldItems);
312 | _oldStartingIndex = oldStartingIndex;
313 | }
314 |
315 | private void InitializeMoveOrReplace(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex, int oldStartingIndex)
316 | {
317 | InitializeAdd(action, newItems, startingIndex);
318 | InitializeRemove(action, oldItems, oldStartingIndex);
319 | }
320 |
321 | //------------------------------------------------------
322 | //
323 | // Public Properties
324 | //
325 | //------------------------------------------------------
326 |
327 | ///
328 | /// The action that caused the event.
329 | ///
330 | public NotifyCollectionChangedAction Action
331 | {
332 | get { return _action; }
333 | }
334 |
335 | ///
336 | /// The items affected by the change.
337 | ///
338 | public IList NewItems
339 | {
340 | get { return _newItems; }
341 | }
342 |
343 | ///
344 | /// The old items affected by the change (for Replace events).
345 | ///
346 | public IList OldItems
347 | {
348 | get { return _oldItems; }
349 | }
350 |
351 | ///
352 | /// The index where the change occurred.
353 | ///
354 | public int NewStartingIndex
355 | {
356 | get { return _newStartingIndex; }
357 | }
358 |
359 | ///
360 | /// The old index where the change occurred (for Move events).
361 | ///
362 | public int OldStartingIndex
363 | {
364 | get { return _oldStartingIndex; }
365 | }
366 |
367 | //------------------------------------------------------
368 | //
369 | // Private Fields
370 | //
371 | //------------------------------------------------------
372 |
373 | private NotifyCollectionChangedAction _action;
374 | private IList _newItems, _oldItems;
375 | private int _newStartingIndex = -1;
376 | private int _oldStartingIndex = -1;
377 | }
378 |
379 | ///
380 | /// The delegate to use for handlers that receive the CollectionChanged event.
381 | ///
382 | public delegate void NotifyCollectionChangedEventHandler(object sender, NotifyCollectionChangedEventArgs e);
383 | }
384 |
385 | #endif
--------------------------------------------------------------------------------
/NotifyCollectionChangedEventArgs.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 5323829f4b4fac94bb590206a59c859e
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/ObservableCollection.cs:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | //
4 | // Copyright (C) 2003 by Microsoft Corporation. All rights reserved.
5 | //
6 | //
7 | //
8 | // Description: Implementation of an Collection implementing INotifyCollectionChanged
9 | // to notify listeners of dynamic changes of the list.
10 | //
11 | // See spec at http://avalon/connecteddata/Specs/Collection%20Interfaces.mht
12 | //
13 | // History:
14 | // 11/22/2004 : [....] - created
15 | //
16 | //---------------------------------------------------------------------------
17 |
18 | // Adapted for Unity
19 |
20 | #if !NETFX_CORE
21 |
22 | using System;
23 | using System.Collections;
24 | using System.Collections.Generic;
25 | using System.Collections.Specialized;
26 | using System.ComponentModel;
27 |
28 | namespace System.Collections.ObjectModel
29 | {
30 | ///
31 | /// Implementation of a dynamic data collection based on generic Collection<T>,
32 | /// implementing INotifyCollectionChanged to notify listeners
33 | /// when items get added, removed or the whole list is refreshed.
34 | ///
35 | public class ObservableCollection : Collection, INotifyCollectionChanged, INotifyPropertyChanged
36 | {
37 | //------------------------------------------------------
38 | //
39 | // Constructors
40 | //
41 | //------------------------------------------------------
42 |
43 | #region Constructors
44 |
45 | ///
46 | /// Initializes a new instance of ObservableCollection that is empty and has default initial capacity.
47 | ///
48 | public ObservableCollection()
49 | : base()
50 | {
51 | }
52 |
53 | ///
54 | /// Initializes a new instance of the ObservableCollection class
55 | /// that contains elements copied from the specified list
56 | ///
57 | /// The list whose elements are copied to the new list.
58 | ///
59 | /// The elements are copied onto the ObservableCollection in the
60 | /// same order they are read by the enumerator of the list.
61 | ///
62 | /// list is a null reference
63 | public ObservableCollection(List list)
64 | : base((list != null) ? new List(list.Count) : list)
65 | {
66 | // Workaround for VSWhidbey bug 562681 (tracked by Windows bug 1369339).
67 | // We should be able to simply call the base(list) ctor. But Collection
68 | // doesn't copy the list (contrary to the documentation) - it uses the
69 | // list directly as its storage. So we do the copying here.
70 | //
71 | CopyFrom(list);
72 | }
73 |
74 | ///
75 | /// Initializes a new instance of the ObservableCollection class that contains
76 | /// elements copied from the specified collection and has sufficient capacity
77 | /// to accommodate the number of elements copied.
78 | ///
79 | /// The collection whose elements are copied to the new list.
80 | ///
81 | /// The elements are copied onto the ObservableCollection in the
82 | /// same order they are read by the enumerator of the collection.
83 | ///
84 | /// collection is a null reference
85 | public ObservableCollection(IEnumerable collection)
86 | {
87 | if (collection == null)
88 | throw new ArgumentNullException("collection");
89 |
90 | CopyFrom(collection);
91 | }
92 |
93 | private void CopyFrom(IEnumerable collection)
94 | {
95 | IList items = Items;
96 | if (collection != null && items != null)
97 | {
98 | using (IEnumerator enumerator = collection.GetEnumerator())
99 | {
100 | while (enumerator.MoveNext())
101 | {
102 | items.Add(enumerator.Current);
103 | }
104 | }
105 | }
106 | }
107 |
108 | #endregion Constructors
109 |
110 | //------------------------------------------------------
111 | //
112 | // Public Methods
113 | //
114 | //------------------------------------------------------
115 |
116 | #region Public Methods
117 |
118 | ///
119 | /// Move item at oldIndex to newIndex.
120 | ///
121 | public void Move(int oldIndex, int newIndex)
122 | {
123 | MoveItem(oldIndex, newIndex);
124 | }
125 |
126 | #endregion Public Methods
127 |
128 | //------------------------------------------------------
129 | //
130 | // Public Events
131 | //
132 | //------------------------------------------------------
133 |
134 | #region Public Events
135 |
136 | //------------------------------------------------------
137 | ///
138 | /// PropertyChanged event (per ).
139 | ///
140 | public virtual event PropertyChangedEventHandler PropertyChanged;
141 |
142 | //------------------------------------------------------
143 | ///
144 | /// Occurs when the collection changes, either by adding or removing an item.
145 | ///
146 | ///
147 | /// see
148 | ///
149 | public virtual event NotifyCollectionChangedEventHandler CollectionChanged;
150 |
151 | #endregion Public Events
152 |
153 | //------------------------------------------------------
154 | //
155 | // Protected Methods
156 | //
157 | //------------------------------------------------------
158 |
159 | #region Protected Methods
160 |
161 | ///
162 | /// Called by base class Collection<T> when the list is being cleared;
163 | /// raises a CollectionChanged event to any listeners.
164 | ///
165 | protected override void ClearItems()
166 | {
167 | CheckReentrancy();
168 | base.ClearItems();
169 | OnPropertyChanged(CountString);
170 | OnPropertyChanged(IndexerName);
171 | OnCollectionReset();
172 | }
173 |
174 | ///
175 | /// Called by base class Collection<T> when an item is removed from list;
176 | /// raises a CollectionChanged event to any listeners.
177 | ///
178 | protected override void RemoveItem(int index)
179 | {
180 | CheckReentrancy();
181 | T removedItem = this[index];
182 |
183 | base.RemoveItem(index);
184 |
185 | OnPropertyChanged(CountString);
186 | OnPropertyChanged(IndexerName);
187 | OnCollectionChanged(NotifyCollectionChangedAction.Remove, removedItem, index);
188 | }
189 |
190 | ///
191 | /// Called by base class Collection<T> when an item is added to list;
192 | /// raises a CollectionChanged event to any listeners.
193 | ///
194 | protected override void InsertItem(int index, T item)
195 | {
196 | CheckReentrancy();
197 | base.InsertItem(index, item);
198 |
199 | OnPropertyChanged(CountString);
200 | OnPropertyChanged(IndexerName);
201 | OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
202 | }
203 |
204 | ///
205 | /// Called by base class Collection<T> when an item is set in list;
206 | /// raises a CollectionChanged event to any listeners.
207 | ///
208 | protected override void SetItem(int index, T item)
209 | {
210 | CheckReentrancy();
211 | T originalItem = this[index];
212 | base.SetItem(index, item);
213 |
214 | OnPropertyChanged(IndexerName);
215 | OnCollectionChanged(NotifyCollectionChangedAction.Replace, originalItem, item, index);
216 | }
217 |
218 | ///
219 | /// Called by base class ObservableCollection<T> when an item is to be moved within the list;
220 | /// raises a CollectionChanged event to any listeners.
221 | ///
222 | protected virtual void MoveItem(int oldIndex, int newIndex)
223 | {
224 | CheckReentrancy();
225 |
226 | T removedItem = this[oldIndex];
227 |
228 | base.RemoveItem(oldIndex);
229 | base.InsertItem(newIndex, removedItem);
230 |
231 | OnPropertyChanged(IndexerName);
232 | OnCollectionChanged(NotifyCollectionChangedAction.Move, removedItem, newIndex, oldIndex);
233 | }
234 |
235 | ///
236 | /// Raises a PropertyChanged event (per ).
237 | ///
238 | protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
239 | {
240 | if (PropertyChanged != null)
241 | {
242 | PropertyChanged(this, e);
243 | }
244 | }
245 |
246 | ///
247 | /// Raise CollectionChanged event to any listeners.
248 | /// Properties/methods modifying this ObservableCollection will raise
249 | /// a collection changed event through this virtual method.
250 | ///
251 | ///
252 | /// When overriding this method, either call its base implementation
253 | /// or call to guard against reentrant collection changes.
254 | ///
255 | protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
256 | {
257 | if (CollectionChanged != null)
258 | {
259 | using (BlockReentrancy())
260 | {
261 | CollectionChanged(this, e);
262 | }
263 | }
264 | }
265 |
266 | ///
267 | /// Disallow reentrant attempts to change this collection. E.g. a event handler
268 | /// of the CollectionChanged event is not allowed to make changes to this collection.
269 | ///
270 | ///
271 | /// typical usage is to wrap e.g. a OnCollectionChanged call with a using() scope:
272 | ///
273 | /// using (BlockReentrancy())
274 | /// {
275 | /// CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, item, index));
276 | /// }
277 | ///
278 | ///
279 | protected IDisposable BlockReentrancy()
280 | {
281 | _monitor.Enter();
282 | return _monitor;
283 | }
284 |
285 | /// Check and assert for reentrant attempts to change this collection.
286 | /// raised when changing the collection
287 | /// while another collection change is still being notified to other listeners
288 | protected void CheckReentrancy()
289 | {
290 | if (_monitor.Busy)
291 | {
292 | // we can allow changes if there's only one listener - the problem
293 | // only arises if reentrant changes make the original event args
294 | // invalid for later listeners. This keeps existing code working
295 | // (e.g. Selector.SelectedItems).
296 | if ((CollectionChanged != null) && (CollectionChanged.GetInvocationList().Length > 1))
297 | throw new InvalidOperationException("Cannot modify the collection while reentrancy is blocked.");
298 | }
299 | }
300 |
301 | #endregion Protected Methods
302 |
303 | //------------------------------------------------------
304 | //
305 | // Private Methods
306 | //
307 | //------------------------------------------------------
308 |
309 | #region Private Methods
310 |
311 | ///
312 | /// Helper to raise a PropertyChanged event />).
313 | ///
314 | private void OnPropertyChanged(string propertyName)
315 | {
316 | OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
317 | }
318 |
319 | ///
320 | /// Helper to raise CollectionChanged event to any listeners
321 | ///
322 | private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index)
323 | {
324 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index));
325 | }
326 |
327 | ///
328 | /// Helper to raise CollectionChanged event to any listeners
329 | ///
330 | private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index, int oldIndex)
331 | {
332 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index, oldIndex));
333 | }
334 |
335 | ///
336 | /// Helper to raise CollectionChanged event to any listeners
337 | ///
338 | private void OnCollectionChanged(NotifyCollectionChangedAction action, object oldItem, object newItem, int index)
339 | {
340 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem, index));
341 | }
342 |
343 | ///
344 | /// Helper to raise CollectionChanged event with action == Reset to any listeners
345 | ///
346 | private void OnCollectionReset()
347 | {
348 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
349 | }
350 |
351 | #endregion Private Methods
352 |
353 | //------------------------------------------------------
354 | //
355 | // Private Types
356 | //
357 | //------------------------------------------------------
358 |
359 | #region Private Types
360 |
361 | // this class helps prevent reentrant calls
362 | private class SimpleMonitor : IDisposable
363 | {
364 | public void Enter()
365 | {
366 | ++_busyCount;
367 | }
368 |
369 | public void Dispose()
370 | {
371 | --_busyCount;
372 | }
373 |
374 | public bool Busy { get { return _busyCount > 0; } }
375 |
376 | private int _busyCount;
377 | }
378 |
379 | #endregion Private Types
380 |
381 | //------------------------------------------------------
382 | //
383 | // Private Fields
384 | //
385 | //------------------------------------------------------
386 |
387 | #region Private Fields
388 |
389 | private const string CountString = "Count";
390 |
391 | // This must agree with Binding.IndexerName. It is declared separately
392 | // here so as to avoid a dependency on PresentationFramework.dll.
393 | private const string IndexerName = "Item[]";
394 |
395 | private SimpleMonitor _monitor = new SimpleMonitor();
396 |
397 | #endregion Private Fields
398 | }
399 | }
400 |
401 | #endif
--------------------------------------------------------------------------------
/ObservableCollection.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 65b19a9acc0ecbd4c9adcfd6167240a0
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | UnityMVVM
2 | =========
3 |
--------------------------------------------------------------------------------