ListWithEvents.cs
1 /*=============================================================================
2 *
3 * (C) Copyright 2011, Michael Carlisle (mike.carlisle@thecodeking.co.uk)
4 *
5 * http://www.TheCodeKing.co.uk
6 *
7 * All rights reserved.
8 * The code and information is provided "as-is" without waranty of any kind,
9 * either expresed or implied.
10 *
11 *-----------------------------------------------------------------------------
12 * History:
13 * 01/09/2007 Michael Carlisle Version 1.0
14 *=============================================================================
15 */
16 using System;
17 using System.Collections;
18 using System.Collections.Generic;
19 
20 namespace sage.ew.formul.ButtonTittle.Utils
21 {
22  internal class ListModificationEventArgs : ListRangeEventArgs
23  {
24  private readonly ListModification modification;
25 
26  public ListModificationEventArgs(ListModification modification, int startIndex, int count)
27  : base(startIndex, count)
28  {
29  this.modification = modification;
30  }
31 
32  public ListModification Modification
33  {
34  get { return modification; }
35  }
36  }
37 
38  internal class ListItemEventArgs : EventArgs
39  {
40  private readonly int itemIndex;
41 
42  public ListItemEventArgs(int itemIndex)
43  {
44  this.itemIndex = itemIndex;
45  }
46 
47  public int ItemIndex
48  {
49  get { return itemIndex; }
50  }
51  }
52 
53  internal class ListRangeEventArgs : EventArgs
54  {
55  private readonly int count;
56  private readonly int startIndex;
57 
58  public ListRangeEventArgs(int startIndex, int count)
59  {
60  this.startIndex = startIndex;
61  this.count = count;
62  }
63 
64  public int StartIndex
65  {
66  get { return startIndex; }
67  }
68 
69  public int Count
70  {
71  get { return count; }
72  }
73  }
74 
75  internal enum ListModification
76  {
80  Cleared = 0,
84  ItemAdded,
88  ItemModified,
92  ItemRemoved,
96  RangeAdded,
100  RangeRemoved
101  }
102 
103  [Serializable]
104  internal class ListWithEvents<T> : List<T>, IList<T>, IList
105  {
106  private readonly object syncRoot = new object();
107  private bool suppressEvents;
108 
109  public ListWithEvents()
110  {
111  }
112 
113  public ListWithEvents(IEnumerable<T> collection)
114  : base(collection)
115  {
116  }
117 
118  public ListWithEvents(int capacity)
119  : base(capacity)
120  {
121  }
122 
123  protected bool EventsSuppressed
124  {
125  get { return suppressEvents; }
126  }
127 
128  #region IList Members
129 
130  public object SyncRoot
131  {
132  get { return syncRoot; }
133  }
134 
135  int IList.Add(object value)
136  {
137  if (value is T)
138  {
139  Add((T) value);
140  return Count - 1;
141  }
142  return -1;
143  }
144 
145  #endregion
146 
147  #region IList<T> Members
148 
149  public new virtual T this[int index]
150  {
151  get { return base[index]; }
152  set
153  {
154  lock (syncRoot)
155  {
156  bool equal = false;
157  if (base[index] != null)
158  {
159  equal = base[index].Equals(value);
160  }
161  else if (base[index] == null && value == null)
162  {
163  equal = true;
164  }
165 
166  if (!equal)
167  {
168  base[index] = value;
169  OnItemModified(new ListItemEventArgs(index));
170  }
171  }
172  }
173  }
174 
175  public new virtual void Add(T item)
176  {
177  int count;
178  lock (syncRoot)
179  {
180  base.Add(item);
181  count = base.Count - 1;
182  }
183  OnItemAdded(new ListItemEventArgs(count));
184  }
185 
186  public new virtual void Clear()
187  {
188  lock (syncRoot)
189  {
190  base.Clear();
191  }
192  OnCleared(EventArgs.Empty);
193  }
194 
195  public new virtual void Insert(int index, T item)
196  {
197  lock (syncRoot)
198  {
199  base.Insert(index, item);
200  }
201  OnItemAdded(new ListItemEventArgs(index));
202  }
203 
204  public new virtual bool Remove(T item)
205  {
206  bool result;
207 
208  lock (syncRoot)
209  {
210  result = base.Remove(item);
211  }
212 
213  // raise the event only if the removal was successful
214  if (result)
215  {
216  OnItemRemoved(EventArgs.Empty);
217  }
218 
219  return result;
220  }
221 
222  public new virtual void RemoveAt(int index)
223  {
224  lock (syncRoot)
225  {
226  base.RemoveAt(index);
227  }
228  OnItemRemoved(EventArgs.Empty);
229  }
230 
231  #endregion
232 
233  public event EventHandler<ListModificationEventArgs> CollectionModified;
234 
235  public event EventHandler Cleared;
236 
237  public event EventHandler<EventArgs> ItemAdded;
238 
239  public event EventHandler<EventArgs> ItemModified;
240 
241  public event EventHandler ItemRemoved;
242 
243  public event EventHandler<ListRangeEventArgs> RangeAdded;
244 
245  public event EventHandler RangeRemoved;
246 
247  public new virtual void AddRange(IEnumerable<T> collection)
248  {
249  lock (syncRoot)
250  {
251  InsertRange(base.Count, collection);
252  }
253  }
254 
255  public new virtual void InsertRange(int index, IEnumerable<T> collection)
256  {
257  int count;
258  lock (syncRoot)
259  {
260  base.InsertRange(index, collection);
261  count = base.Count - index;
262  }
263  OnRangeAdded(new ListRangeEventArgs(index, count));
264  }
265 
266  public new virtual int RemoveAll(Predicate<T> match)
267  {
268  int count;
269 
270  lock (syncRoot)
271  {
272  count = base.RemoveAll(match);
273  }
274 
275  // raise the event only if the removal was successful
276  if (count > 0)
277  {
278  OnRangeRemoved(EventArgs.Empty);
279  }
280 
281  return count;
282  }
283 
290  public new virtual void RemoveRange(int index, int count)
291  {
292  int listCountOld, listCountNew;
293  lock (syncRoot)
294  {
295  listCountOld = base.Count;
296  base.RemoveRange(index, count);
297  listCountNew = base.Count;
298  }
299 
300  // raise the event only if the removal was successful
301  if (listCountOld != listCountNew)
302  {
303  OnRangeRemoved(EventArgs.Empty);
304  }
305  }
306 
307  public virtual void RemoveRange(List<T> collection)
308  {
309  for (int i = 0; i < collection.Count; i++)
310  {
311  Remove(collection[i]);
312  }
313  }
314 
315  public void SuppressEvents()
316  {
317  suppressEvents = true;
318  }
319 
320  public void ResumeEvents()
321  {
322  suppressEvents = false;
323  }
324 
325  protected virtual void OnCleared(EventArgs e)
326  {
327  if (suppressEvents)
328  {
329  return;
330  }
331 
332  if (Cleared != null)
333  {
334  Cleared(this, e);
335  }
336 
337  OnCollectionModified(new ListModificationEventArgs(ListModification.Cleared, -1, -1));
338  }
339 
340  protected virtual void OnCollectionModified(ListModificationEventArgs e)
341  {
342  if (suppressEvents)
343  {
344  return;
345  }
346 
347  if (CollectionModified != null)
348  {
349  CollectionModified(this, e);
350  }
351  }
352 
353  protected virtual void OnItemAdded(ListItemEventArgs e)
354  {
355  if (suppressEvents)
356  {
357  return;
358  }
359 
360  if (ItemAdded != null)
361  {
362  ItemAdded(this, e);
363  }
364 
365  OnCollectionModified(new ListModificationEventArgs(ListModification.ItemAdded, e.ItemIndex, 1));
366  }
367 
368  protected virtual void OnItemModified(ListItemEventArgs e)
369  {
370  if (suppressEvents)
371  {
372  return;
373  }
374 
375  if (ItemModified != null)
376  {
377  ItemModified(this, e);
378  }
379 
380  OnCollectionModified(new ListModificationEventArgs(ListModification.ItemModified, e.ItemIndex, 1));
381  }
382 
383  protected virtual void OnItemRemoved(EventArgs e)
384  {
385  if (suppressEvents)
386  {
387  return;
388  }
389 
390  if (ItemRemoved != null)
391  {
392  ItemRemoved(this, e);
393  }
394 
395  OnCollectionModified(new ListModificationEventArgs(ListModification.ItemRemoved, -1, 1));
396  }
397 
398  protected virtual void OnRangeAdded(ListRangeEventArgs e)
399  {
400  if (suppressEvents)
401  {
402  return;
403  }
404 
405  if (RangeAdded != null)
406  {
407  RangeAdded(this, e);
408  }
409 
410  OnCollectionModified(new ListModificationEventArgs(ListModification.RangeAdded, e.StartIndex, e.Count));
411  }
412 
413  protected virtual void OnRangeRemoved(EventArgs e)
414  {
415  if (suppressEvents)
416  {
417  return;
418  }
419 
420  if (RangeRemoved != null)
421  {
422  RangeRemoved(this, e);
423  }
424 
425  OnCollectionModified(new ListModificationEventArgs(ListModification.RangeRemoved, -1, -1));
426  }
427  }
428 }