Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Collections/3.3/ObservableList.cs @ 2879

Last change on this file since 2879 was 2832, checked in by swagner, 15 years ago

Moved CollectionItemsChanged events into own interfaces (#819)

File size: 15.5 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections;
24using System.Collections.Generic;
25using System.ComponentModel;
26using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
27
28namespace HeuristicLab.Collections {
29  [Serializable]
30  public class ObservableList<T> : IObservableList<T> {
31    [Storable]
32    private List<T> list;
33
34    #region Properties
35    public int Capacity {
36      get { return list.Capacity; }
37      set {
38        if (list.Capacity != value) {
39          list.Capacity = value;
40          OnPropertyChanged("Capacity");
41        }
42      }
43    }
44    public int Count {
45      get { return list.Count; }
46    }
47    bool ICollection<T>.IsReadOnly {
48      get { return ((ICollection<T>)list).IsReadOnly; }
49    }
50
51    public T this[int index] {
52      get {
53        return list[index];
54      }
55      set {
56        T item = list[index];
57        if (!((item == null) && (value == null)) && ((item == null) || (!item.Equals(value)))) {
58          list[index] = value;
59          OnItemsReplaced(new IndexedItem<T>[] { new IndexedItem<T>(index, value) }, new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
60          OnPropertyChanged("Item[]");
61        }
62      }
63    }
64    #endregion
65
66    #region Constructors
67    public ObservableList() {
68      list = new List<T>();
69    }
70    public ObservableList(int capacity) {
71      list = new List<T>(capacity);
72    }
73    public ObservableList(IEnumerable<T> collection) {
74      list = new List<T>(collection);
75    }
76    #endregion
77
78    #region Access
79    public List<T> GetRange(int index, int count) {
80      return list.GetRange(index, count);
81    }
82
83    public bool Contains(T item) {
84      return list.Contains(item);
85    }
86
87    public int IndexOf(T item) {
88      return list.IndexOf(item);
89    }
90    public int IndexOf(T item, int index) {
91      return list.IndexOf(item, index);
92    }
93    public int IndexOf(T item, int index, int count) {
94      return list.IndexOf(item, index, count);
95    }
96
97    public int LastIndexOf(T item) {
98      return list.LastIndexOf(item);
99    }
100    public int LastIndexOf(T item, int index) {
101      return list.LastIndexOf(item, index);
102    }
103    public int LastIndexOf(T item, int index, int count) {
104      return list.LastIndexOf(item, index, count);
105    }
106
107    public int BinarySearch(T item) {
108      return list.BinarySearch(item);
109    }
110    public int BinarySearch(T item, IComparer<T> comparer) {
111      return list.BinarySearch(item, comparer);
112    }
113    public int BinarySearch(int index, int count, T item, IComparer<T> comparer) {
114      return list.BinarySearch(index, count, item, comparer);
115    }
116
117    public bool Exists(Predicate<T> match) {
118      return list.Exists(match);
119    }
120
121    public T Find(Predicate<T> match) {
122      return list.Find(match);
123    }
124    public List<T> FindAll(Predicate<T> match) {
125      return list.FindAll(match);
126    }
127    public T FindLast(Predicate<T> match) {
128      return list.FindLast(match);
129    }
130
131    public int FindIndex(Predicate<T> match) {
132      return list.FindIndex(match);
133    }
134    public int FindIndex(int startIndex, Predicate<T> match) {
135      return list.FindIndex(startIndex, match);
136    }
137    public int FindIndex(int startIndex, int count, Predicate<T> match) {
138      return list.FindIndex(startIndex, count, match);
139    }
140
141    public int FindLastIndex(Predicate<T> match) {
142      return list.FindLastIndex(match);
143    }
144    public int FindLastIndex(int startIndex, Predicate<T> match) {
145      return list.FindLastIndex(startIndex, match);
146    }
147    public int FindLastIndex(int startIndex, int count, Predicate<T> match) {
148      return list.FindLastIndex(startIndex, count, match);
149    }
150    #endregion
151
152    #region Manipulation
153    public void Add(T item) {
154      int capacity = list.Capacity;
155      list.Add(item);
156      if (list.Capacity != capacity)
157        OnPropertyChanged("Capacity");
158      OnPropertyChanged("Item[]");
159      OnPropertyChanged("Count");
160      OnItemsAdded(new IndexedItem<T>[] { new IndexedItem<T>(list.Count - 1, item) });
161      OnItemsAdded(new T[] { item });
162    }
163    public void AddRange(IEnumerable<T> collection) {
164      int capacity = list.Capacity;
165      int index = list.Count;
166      list.AddRange(collection);
167      List<IndexedItem<T>> items = new List<IndexedItem<T>>();
168      foreach (T item in collection) {
169        items.Add(new IndexedItem<T>(index, item));
170        index++;
171      }
172      if (items.Count > 0) {
173        if (list.Capacity != capacity)
174          OnPropertyChanged("Capacity");
175        OnPropertyChanged("Item[]");
176        OnPropertyChanged("Count");
177        OnItemsAdded(items);
178        OnItemsAdded(collection);
179      }
180    }
181
182    public void Insert(int index, T item) {
183      int capacity = list.Capacity;
184      list.Insert(index, item);
185      if (list.Capacity != capacity)
186        OnPropertyChanged("Capacity");
187      OnPropertyChanged("Item[]");
188      OnPropertyChanged("Count");
189      OnItemsAdded(new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
190      OnItemsAdded(new T[] { item });
191    }
192    public void InsertRange(int index, IEnumerable<T> collection) {
193      int capacity = list.Capacity;
194      list.InsertRange(index, collection);
195      List<IndexedItem<T>> items = new List<IndexedItem<T>>();
196      foreach (T item in collection) {
197        items.Add(new IndexedItem<T>(index, item));
198        index++;
199      }
200      if (items.Count > 0) {
201        if (list.Capacity != capacity)
202          OnPropertyChanged("Capacity");
203        OnPropertyChanged("Item[]");
204        OnPropertyChanged("Count");
205        OnItemsAdded(items);
206        OnItemsAdded(collection);
207      }
208    }
209
210    public bool Remove(T item) {
211      int index = list.IndexOf(item);
212      if (index != -1) {
213        list.RemoveAt(index);
214        OnPropertyChanged("Item[]");
215        OnPropertyChanged("Count");
216        OnItemsRemoved(new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
217        OnItemsRemoved(new T[] { item });
218        return true;
219      }
220      return false;
221    }
222    public int RemoveAll(Predicate<T> match) {
223      if (match == null) throw new ArgumentNullException();
224      List<IndexedItem<T>> indexedItems = new List<IndexedItem<T>>();
225      List<T> items = new List<T>();
226      for (int i = 0; i < list.Count; i++) {
227        if (match(list[i])) {
228          indexedItems.Add(new IndexedItem<T>(i, list[i]));
229          items.Add(list[i]);
230        }
231      }
232      int result = 0;
233      if (indexedItems.Count > 0) {
234        result = list.RemoveAll(match);
235        OnPropertyChanged("Item[]");
236        OnPropertyChanged("Count");
237        OnItemsRemoved(indexedItems);
238        OnItemsRemoved(items);
239      }
240      return result;
241    }
242    public void RemoveAt(int index) {
243      T item = list[index];
244      list.RemoveAt(index);
245      OnPropertyChanged("Item[]");
246      OnPropertyChanged("Count");
247      OnItemsRemoved(new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
248      OnItemsRemoved(new T[] { item });
249    }
250    public void RemoveRange(int index, int count) {
251      if (count > 0) {
252        IndexedItem<T>[] indexedItems = GetIndexedItems(index, count);
253        T[] items = new T[count];
254        list.CopyTo(index, items, 0, count);
255        list.RemoveRange(index, count);
256        OnPropertyChanged("Item[]");
257        OnPropertyChanged("Count");
258        OnItemsRemoved(indexedItems);
259        OnItemsRemoved(items);
260      }
261    }
262
263    public void Clear() {
264      if (list.Count > 0) {
265        IndexedItem<T>[] indexedItems = GetIndexedItems();
266        T[] items = list.ToArray();
267        list.Clear();
268        OnPropertyChanged("Item[]");
269        OnPropertyChanged("Count");
270        OnCollectionReset(new IndexedItem<T>[0], indexedItems);
271        OnCollectionReset(new T[0], items);
272      }
273    }
274
275    public void Reverse() {
276      if (list.Count > 1) {
277        IndexedItem<T>[] oldItems = GetIndexedItems();
278        list.Reverse();
279        OnPropertyChanged("Item[]");
280        OnItemsMoved(GetIndexedItems(), oldItems);
281      }
282    }
283    public void Reverse(int index, int count) {
284      if (count > 1) {
285        IndexedItem<T>[] oldItems = GetIndexedItems(index, count);
286        list.Reverse(index, count);
287        OnPropertyChanged("Item[]");
288        OnItemsMoved(GetIndexedItems(index, count), oldItems);
289      }
290    }
291
292    public void Sort() {
293      if (list.Count > 1) {
294        IndexedItem<T>[] oldItems = GetIndexedItems();
295        list.Sort();
296        OnPropertyChanged("Item[]");
297        OnItemsMoved(GetIndexedItems(), oldItems);
298      }
299    }
300    public void Sort(Comparison<T> comparison) {
301      if (list.Count > 1) {
302        IndexedItem<T>[] oldItems = GetIndexedItems();
303        list.Sort(comparison);
304        OnPropertyChanged("Item[]");
305        OnItemsMoved(GetIndexedItems(), oldItems);
306      }
307    }
308    public void Sort(IComparer<T> comparer) {
309      if (list.Count > 1) {
310        IndexedItem<T>[] oldItems = GetIndexedItems();
311        list.Sort(comparer);
312        OnPropertyChanged("Item[]");
313        OnItemsMoved(GetIndexedItems(), oldItems);
314      }
315    }
316    public void Sort(int index, int count, IComparer<T> comparer) {
317      if (count > 1) {
318        IndexedItem<T>[] oldItems = GetIndexedItems(index, count);
319        list.Sort(index, count, comparer);
320        OnPropertyChanged("Item[]");
321        OnItemsMoved(GetIndexedItems(index, count), oldItems);
322      }
323    }
324    #endregion
325
326    #region Conversion
327    public ReadOnlyObservableList<T> AsReadOnly() {
328      return new ReadOnlyObservableList<T>(this);
329    }
330    public T[] ToArray() {
331      return list.ToArray();
332    }
333    public void CopyTo(T[] array) {
334      list.CopyTo(array);
335    }
336    public void CopyTo(T[] array, int arrayIndex) {
337      list.CopyTo(array, arrayIndex);
338    }
339    public void CopyTo(int index, T[] array, int arrayIndex, int count) {
340      list.CopyTo(index, array, arrayIndex, count);
341    }
342    public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter) {
343      return list.ConvertAll<TOutput>(converter);
344    }
345    #endregion
346
347    #region Processing
348    public void ForEach(Action<T> action) {
349      list.ForEach(action);
350    }
351    public bool TrueForAll(Predicate<T> match) {
352      return list.TrueForAll(match);
353    }
354    #endregion
355
356    #region Enumeration
357    public IEnumerator<T> GetEnumerator() {
358      return list.GetEnumerator();
359    }
360    IEnumerator IEnumerable.GetEnumerator() {
361      return list.GetEnumerator();
362    }
363    #endregion
364
365    #region Helpers
366    public void TrimExcess() {
367      int capacity = list.Capacity;
368      list.TrimExcess();
369      if (list.Capacity != capacity)
370        OnPropertyChanged("Capacity");
371    }
372    #endregion
373
374    #region Events
375    [field: NonSerialized]
376    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsAdded;
377    protected virtual void OnItemsAdded(IEnumerable<IndexedItem<T>> items) {
378      if (ItemsAdded != null)
379        ItemsAdded(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items));
380    }
381
382    [field: NonSerialized]
383    private event CollectionItemsChangedEventHandler<T> itemsAdded;
384    event CollectionItemsChangedEventHandler<T> INotifyObservableCollectionItemsChanged<T>.ItemsAdded {
385      add { itemsAdded += value; }
386      remove { itemsAdded -= value; }
387    }
388    private void OnItemsAdded(IEnumerable<T> items) {
389      if (itemsAdded != null)
390        itemsAdded(this, new CollectionItemsChangedEventArgs<T>(items));
391    }
392
393    [field: NonSerialized]
394    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsRemoved;
395    protected virtual void OnItemsRemoved(IEnumerable<IndexedItem<T>> items) {
396      if (ItemsRemoved != null)
397        ItemsRemoved(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items));
398    }
399
400    [field: NonSerialized]
401    private event CollectionItemsChangedEventHandler<T> itemsRemoved;
402    event CollectionItemsChangedEventHandler<T> INotifyObservableCollectionItemsChanged<T>.ItemsRemoved {
403      add { itemsRemoved += value; }
404      remove { itemsRemoved -= value; }
405    }
406    private void OnItemsRemoved(IEnumerable<T> items) {
407      if (itemsRemoved != null)
408        itemsRemoved(this, new CollectionItemsChangedEventArgs<T>(items));
409    }
410
411    [field: NonSerialized]
412    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsReplaced;
413    protected virtual void OnItemsReplaced(IEnumerable<IndexedItem<T>> items, IEnumerable<IndexedItem<T>> oldItems) {
414      if (ItemsReplaced != null)
415        ItemsReplaced(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
416    }
417
418    [field: NonSerialized]
419    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsMoved;
420    protected virtual void OnItemsMoved(IEnumerable<IndexedItem<T>> items, IEnumerable<IndexedItem<T>> oldItems) {
421      if (ItemsMoved != null)
422        ItemsMoved(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
423    }
424
425    [field: NonSerialized]
426    public event CollectionItemsChangedEventHandler<IndexedItem<T>> CollectionReset;
427    protected virtual void OnCollectionReset(IEnumerable<IndexedItem<T>> items, IEnumerable<IndexedItem<T>> oldItems) {
428      if (CollectionReset != null)
429        CollectionReset(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
430    }
431
432    [field: NonSerialized]
433    private event CollectionItemsChangedEventHandler<T> collectionReset;
434    event CollectionItemsChangedEventHandler<T> INotifyObservableCollectionItemsChanged<T>.CollectionReset {
435      add { collectionReset += value; }
436      remove { collectionReset -= value; }
437    }
438    private void OnCollectionReset(IEnumerable<T> items, IEnumerable<T> oldItems) {
439      if (collectionReset != null)
440        collectionReset(this, new CollectionItemsChangedEventArgs<T>(items, oldItems));
441    }
442
443    [field: NonSerialized]
444    public event PropertyChangedEventHandler PropertyChanged;
445    protected virtual void OnPropertyChanged(string propertyName) {
446      if (PropertyChanged != null)
447        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
448    }
449    #endregion
450
451    #region Private helpers
452    private IndexedItem<T>[] GetIndexedItems() {
453      IndexedItem<T>[] items = new IndexedItem<T>[list.Count];
454      for (int i = 0; i < list.Count; i++)
455        items[i] = new IndexedItem<T>(i, list[i]);
456      return items;
457    }
458    private IndexedItem<T>[] GetIndexedItems(int index, int count) {
459      IndexedItem<T>[] items = new IndexedItem<T>[count];
460      for (int i = 0; i < count; i++)
461        items[i] = new IndexedItem<T>(index + i, list[index + i]);
462      return items;
463    }
464    #endregion
465  }
466}
Note: See TracBrowser for help on using the repository browser.