2 Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
3 Permission is hereby granted, free of charge, to any person obtaining a copy
4 of this software and associated documentation files (the "Software"), to deal
5 in the Software without restriction, including without limitation the rights
6 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 copies of the Software, and to permit persons to whom the Software is
8 furnished to do so, subject to the following conditions:
10 The above copyright notice and this permission notice shall be included in
11 all copies or substantial portions of the Software.
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 using System.Diagnostics;
24 using SCG = System.Collections.Generic;
32 public enum EventTypeEnum
61 Inserted = 0x00000010,
65 RemovedAt = 0x00000020,
73 /// Holds the real events for a collection
75 /// <typeparam name="T"></typeparam>
77 internal sealed class EventBlock<T>
79 internal EventTypeEnum events;
81 event CollectionChangedHandler<T> collectionChanged;
82 internal event CollectionChangedHandler<T> CollectionChanged
86 collectionChanged += value;
87 events |= EventTypeEnum.Changed;
91 collectionChanged -= value;
92 if (collectionChanged == null)
93 events &= ~EventTypeEnum.Changed;
96 internal void raiseCollectionChanged(object sender)
97 { if (collectionChanged != null) collectionChanged(sender); }
99 event CollectionClearedHandler<T> collectionCleared;
100 internal event CollectionClearedHandler<T> CollectionCleared
104 collectionCleared += value;
105 events |= EventTypeEnum.Cleared;
109 collectionCleared -= value;
110 if (collectionCleared == null)
111 events &= ~EventTypeEnum.Cleared;
114 internal void raiseCollectionCleared(object sender, bool full, int count)
115 { if (collectionCleared != null) collectionCleared(sender, new ClearedEventArgs(full, count)); }
116 internal void raiseCollectionCleared(object sender, bool full, int count, int? start)
117 { if (collectionCleared != null) collectionCleared(sender, new ClearedRangeEventArgs(full, count, start)); }
119 event ItemsAddedHandler<T> itemsAdded;
120 internal event ItemsAddedHandler<T> ItemsAdded
125 events |= EventTypeEnum.Added;
130 if (itemsAdded == null)
131 events &= ~EventTypeEnum.Added;
134 internal void raiseItemsAdded(object sender, T item, int count)
135 { if (itemsAdded != null) itemsAdded(sender, new ItemCountEventArgs<T>(item, count)); }
137 event ItemsRemovedHandler<T> itemsRemoved;
138 internal event ItemsRemovedHandler<T> ItemsRemoved
142 itemsRemoved += value;
143 events |= EventTypeEnum.Removed;
147 itemsRemoved -= value;
148 if (itemsRemoved == null)
149 events &= ~EventTypeEnum.Removed;
152 internal void raiseItemsRemoved(object sender, T item, int count)
153 { if (itemsRemoved != null) itemsRemoved(sender, new ItemCountEventArgs<T>(item, count)); }
155 event ItemInsertedHandler<T> itemInserted;
156 internal event ItemInsertedHandler<T> ItemInserted
160 itemInserted += value;
161 events |= EventTypeEnum.Inserted;
165 itemInserted -= value;
166 if (itemInserted == null)
167 events &= ~EventTypeEnum.Inserted;
170 internal void raiseItemInserted(object sender, T item, int index)
171 { if (itemInserted != null) itemInserted(sender, new ItemAtEventArgs<T>(item, index)); }
173 event ItemRemovedAtHandler<T> itemRemovedAt;
174 internal event ItemRemovedAtHandler<T> ItemRemovedAt
178 itemRemovedAt += value;
179 events |= EventTypeEnum.RemovedAt;
183 itemRemovedAt -= value;
184 if (itemRemovedAt == null)
185 events &= ~EventTypeEnum.RemovedAt;
188 internal void raiseItemRemovedAt(object sender, T item, int index)
189 { if (itemRemovedAt != null) itemRemovedAt(sender, new ItemAtEventArgs<T>(item, index)); }
193 /// Tentative, to conserve memory in GuardedCollectionValueBase
194 /// This should really be nested in Guarded collection value, only have a guardereal field
196 /// <typeparam name="T"></typeparam>
198 internal sealed class ProxyEventBlock<T>
200 ICollectionValue<T> proxy, real;
202 internal ProxyEventBlock(ICollectionValue<T> proxy, ICollectionValue<T> real)
203 { this.proxy = proxy; this.real = real; }
205 event CollectionChangedHandler<T> collectionChanged;
206 CollectionChangedHandler<T> collectionChangedProxy;
207 internal event CollectionChangedHandler<T> CollectionChanged
211 if (collectionChanged == null)
213 if (collectionChangedProxy == null)
214 collectionChangedProxy = delegate(object sender) { collectionChanged(proxy); };
215 real.CollectionChanged += collectionChangedProxy;
217 collectionChanged += value;
221 collectionChanged -= value;
222 if (collectionChanged == null)
223 real.CollectionChanged -= collectionChangedProxy;
227 event CollectionClearedHandler<T> collectionCleared;
228 CollectionClearedHandler<T> collectionClearedProxy;
229 internal event CollectionClearedHandler<T> CollectionCleared
233 if (collectionCleared == null)
235 if (collectionClearedProxy == null)
236 collectionClearedProxy = delegate(object sender, ClearedEventArgs e) { collectionCleared(proxy, e); };
237 real.CollectionCleared += collectionClearedProxy;
239 collectionCleared += value;
243 collectionCleared -= value;
244 if (collectionCleared == null)
245 real.CollectionCleared -= collectionClearedProxy;
249 event ItemsAddedHandler<T> itemsAdded;
250 ItemsAddedHandler<T> itemsAddedProxy;
251 internal event ItemsAddedHandler<T> ItemsAdded
255 if (itemsAdded == null)
257 if (itemsAddedProxy == null)
258 itemsAddedProxy = delegate(object sender, ItemCountEventArgs<T> e) { itemsAdded(proxy, e); };
259 real.ItemsAdded += itemsAddedProxy;
266 if (itemsAdded == null)
267 real.ItemsAdded -= itemsAddedProxy;
271 event ItemInsertedHandler<T> itemInserted;
272 ItemInsertedHandler<T> itemInsertedProxy;
273 internal event ItemInsertedHandler<T> ItemInserted
277 if (itemInserted == null)
279 if (itemInsertedProxy == null)
280 itemInsertedProxy = delegate(object sender, ItemAtEventArgs<T> e) { itemInserted(proxy, e); };
281 real.ItemInserted += itemInsertedProxy;
283 itemInserted += value;
287 itemInserted -= value;
288 if (itemInserted == null)
289 real.ItemInserted -= itemInsertedProxy;
293 event ItemsRemovedHandler<T> itemsRemoved;
294 ItemsRemovedHandler<T> itemsRemovedProxy;
295 internal event ItemsRemovedHandler<T> ItemsRemoved
299 if (itemsRemoved == null)
301 if (itemsRemovedProxy == null)
302 itemsRemovedProxy = delegate(object sender, ItemCountEventArgs<T> e) { itemsRemoved(proxy, e); };
303 real.ItemsRemoved += itemsRemovedProxy;
305 itemsRemoved += value;
309 itemsRemoved -= value;
310 if (itemsRemoved == null)
311 real.ItemsRemoved -= itemsRemovedProxy;
315 event ItemRemovedAtHandler<T> itemRemovedAt;
316 ItemRemovedAtHandler<T> itemRemovedAtProxy;
317 internal event ItemRemovedAtHandler<T> ItemRemovedAt
321 if (itemRemovedAt == null)
323 if (itemRemovedAtProxy == null)
324 itemRemovedAtProxy = delegate(object sender, ItemAtEventArgs<T> e) { itemRemovedAt(proxy, e); };
325 real.ItemRemovedAt += itemRemovedAtProxy;
327 itemRemovedAt += value;
331 itemRemovedAt -= value;
332 if (itemRemovedAt == null)
333 real.ItemRemovedAt -= itemRemovedAtProxy;
341 /// <typeparam name="T"></typeparam>
342 public class ItemAtEventArgs<T> : EventArgs
347 public readonly T Item;
351 public readonly int Index;
355 /// <param name="item"></param>
356 /// <param name="index"></param>
357 public ItemAtEventArgs(T item, int index) { Item = item; Index = index; }
361 /// <returns></returns>
362 public override string ToString()
364 return String.Format("(ItemAtEventArgs {0} '{1}')", Index, Item);
371 /// <typeparam name="T"></typeparam>
372 public class ItemCountEventArgs<T> : EventArgs
377 public readonly T Item;
381 public readonly int Count;
385 /// <param name="count"></param>
386 /// <param name="item"></param>
387 public ItemCountEventArgs(T item, int count) { Item = item; Count = count; }
391 /// <returns></returns>
392 public override string ToString()
394 return String.Format("(ItemCountEventArgs {0} '{1}')", Count, Item);
403 public class ClearedEventArgs : EventArgs
408 public readonly bool Full;
412 public readonly int Count;
417 /// <param name="full">True if the operation cleared all of the collection</param>
418 /// <param name="count">The number of items removed by the clear.</param>
419 public ClearedEventArgs(bool full, int count) { Full = full; Count = count; }
423 /// <returns></returns>
424 public override string ToString()
426 return String.Format("(ClearedEventArgs {0} {1})", Count, Full);
433 public class ClearedRangeEventArgs : ClearedEventArgs
435 //WE could let this be of type int? to allow
439 public readonly int? Start;
443 /// <param name="full"></param>
444 /// <param name="count"></param>
445 /// <param name="start"></param>
446 public ClearedRangeEventArgs(bool full, int count, int? start) : base(full,count) { Start = start; }
450 /// <returns></returns>
451 public override string ToString()
453 return String.Format("(ClearedRangeEventArgs {0} {1} {2})", Count, Full, Start);
458 /// The type of event raised after an operation on a collection has changed its contents.
459 /// Normally, a multioperation like AddAll,
460 /// <see cref="M:C5.IExtensible`1.AddAll(System.Collections.Generic.IEnumerable{`0})"/>
461 /// will only fire one CollectionChanged event. Any operation that changes the collection
462 /// must fire CollectionChanged as its last event.
464 public delegate void CollectionChangedHandler<T>(object sender);
467 /// The type of event raised after the Clear() operation on a collection.
469 /// Note: The Clear() operation will not fire ItemsRemoved events.
471 /// <param name="sender"></param>
472 /// <param name="eventArgs"></param>
473 public delegate void CollectionClearedHandler<T>(object sender, ClearedEventArgs eventArgs);
476 /// The type of event raised after an item has been added to a collection.
477 /// The event will be raised at a point of time, where the collection object is
478 /// in an internally consistent state and before the corresponding CollectionChanged
481 /// Note: an Update operation will fire an ItemsRemoved and an ItemsAdded event.
483 /// Note: When an item is inserted into a list (<see cref="T:C5.IList`1"/>), both
484 /// ItemInserted and ItemsAdded events will be fired.
486 /// <param name="sender"></param>
487 /// <param name="eventArgs">An object with the item that was added</param>
488 public delegate void ItemsAddedHandler<T>(object sender, ItemCountEventArgs<T> eventArgs);
491 /// The type of event raised after an item has been removed from a collection.
492 /// The event will be raised at a point of time, where the collection object is
493 /// in an internally consistent state and before the corresponding CollectionChanged
496 /// Note: The Clear() operation will not fire ItemsRemoved events.
498 /// Note: an Update operation will fire an ItemsRemoved and an ItemsAdded event.
500 /// Note: When an item is removed from a list by the RemoveAt operation, both an
501 /// ItemsRemoved and an ItemRemovedAt event will be fired.
503 /// <param name="sender"></param>
504 /// <param name="eventArgs">An object with the item that was removed</param>
505 public delegate void ItemsRemovedHandler<T>(object sender, ItemCountEventArgs<T> eventArgs);
508 /// The type of event raised after an item has been inserted into a list by an Insert,
509 /// InsertFirst or InsertLast operation.
510 /// The event will be raised at a point of time, where the collection object is
511 /// in an internally consistent state and before the corresponding CollectionChanged
514 /// Note: an ItemsAdded event will also be fired.
516 /// <param name="sender"></param>
517 /// <param name="eventArgs"></param>
518 public delegate void ItemInsertedHandler<T>(object sender, ItemAtEventArgs<T> eventArgs);
521 /// The type of event raised after an item has been removed from a list by a RemoveAt(int i)
522 /// operation (or RemoveFirst(), RemoveLast(), Remove() operation).
523 /// The event will be raised at a point of time, where the collection object is
524 /// in an internally consistent state and before the corresponding CollectionChanged
527 /// Note: an ItemRemoved event will also be fired.
529 /// <param name="sender"></param>
530 /// <param name="eventArgs"></param>
531 public delegate void ItemRemovedAtHandler<T>(object sender, ItemAtEventArgs<T> eventArgs);