Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 9019 was 8610, checked in by mkommend, 12 years ago

#1946:

  • Added 'ObservableKeyedList` and related classes
  • Reordered firing events in ObservableList
  • Adapted cloning ctor of ReadOnlyItemList
File size: 17.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 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 System.Linq;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28
29namespace HeuristicLab.Collections {
30  [StorableClass]
31  [Serializable]
32  public class ObservableList<T> : IObservableList<T> {
33    [Storable]
34    protected List<T> list;
35
36    #region Properties
37    public int Capacity {
38      get { return list.Capacity; }
39      set {
40        if (list.Capacity != value) {
41          list.Capacity = value;
42          OnPropertyChanged("Capacity");
43        }
44      }
45    }
46    public int Count {
47      get { return list.Count; }
48    }
49    bool ICollection<T>.IsReadOnly {
50      get { return ((ICollection<T>)list).IsReadOnly; }
51    }
52
53    public T this[int index] {
54      get {
55        return list[index];
56      }
57      set {
58        T item = list[index];
59        if (!((item == null) && (value == null)) && ((item == null) || (!item.Equals(value)))) {
60          list[index] = value;
61          OnItemsReplaced(new IndexedItem<T>[] { new IndexedItem<T>(index, value) }, new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
62          OnPropertyChanged("Item[]");
63        }
64      }
65    }
66    #endregion
67
68    #region Constructors
69    public ObservableList() {
70      list = new List<T>();
71    }
72    public ObservableList(int capacity) {
73      list = new List<T>(capacity);
74    }
75    public ObservableList(IEnumerable<T> collection) {
76      list = new List<T>(collection);
77    }
78    [StorableConstructor]
79    protected ObservableList(bool deserializing) { }
80    #endregion
81
82    #region Access
83    public List<T> GetRange(int index, int count) {
84      return list.GetRange(index, count);
85    }
86
87    public bool Contains(T item) {
88      return list.Contains(item);
89    }
90
91    public int IndexOf(T item) {
92      return list.IndexOf(item);
93    }
94    public int IndexOf(T item, int index) {
95      return list.IndexOf(item, index);
96    }
97    public int IndexOf(T item, int index, int count) {
98      return list.IndexOf(item, index, count);
99    }
100
101    public int LastIndexOf(T item) {
102      return list.LastIndexOf(item);
103    }
104    public int LastIndexOf(T item, int index) {
105      return list.LastIndexOf(item, index);
106    }
107    public int LastIndexOf(T item, int index, int count) {
108      return list.LastIndexOf(item, index, count);
109    }
110
111    public int BinarySearch(T item) {
112      return list.BinarySearch(item);
113    }
114    public int BinarySearch(T item, IComparer<T> comparer) {
115      return list.BinarySearch(item, comparer);
116    }
117    public int BinarySearch(int index, int count, T item, IComparer<T> comparer) {
118      return list.BinarySearch(index, count, item, comparer);
119    }
120
121    public bool Exists(Predicate<T> match) {
122      return list.Exists(match);
123    }
124
125    public T Find(Predicate<T> match) {
126      return list.Find(match);
127    }
128    public List<T> FindAll(Predicate<T> match) {
129      return list.FindAll(match);
130    }
131    public T FindLast(Predicate<T> match) {
132      return list.FindLast(match);
133    }
134
135    public int FindIndex(Predicate<T> match) {
136      return list.FindIndex(match);
137    }
138    public int FindIndex(int startIndex, Predicate<T> match) {
139      return list.FindIndex(startIndex, match);
140    }
141    public int FindIndex(int startIndex, int count, Predicate<T> match) {
142      return list.FindIndex(startIndex, count, match);
143    }
144
145    public int FindLastIndex(Predicate<T> match) {
146      return list.FindLastIndex(match);
147    }
148    public int FindLastIndex(int startIndex, Predicate<T> match) {
149      return list.FindLastIndex(startIndex, match);
150    }
151    public int FindLastIndex(int startIndex, int count, Predicate<T> match) {
152      return list.FindLastIndex(startIndex, count, match);
153    }
154    #endregion
155
156    #region Manipulation
157    public void Add(T item) {
158      int capacity = list.Capacity;
159      list.Add(item);
160      OnItemsAdded(new IndexedItem<T>[] { new IndexedItem<T>(list.Count - 1, item) });
161      OnItemsAdded(new T[] { item });
162      if (list.Capacity != capacity)
163        OnPropertyChanged("Capacity");
164      OnPropertyChanged("Item[]");
165      OnPropertyChanged("Count");
166    }
167    public void AddRange(IEnumerable<T> collection) {
168      int capacity = list.Capacity;
169      int index = list.Count;
170      list.AddRange(collection);
171      List<IndexedItem<T>> items = new List<IndexedItem<T>>();
172      foreach (T item in collection) {
173        items.Add(new IndexedItem<T>(index, item));
174        index++;
175      }
176      if (items.Count > 0) {
177        OnItemsAdded(items);
178        OnItemsAdded(collection);
179        if (list.Capacity != capacity)
180          OnPropertyChanged("Capacity");
181        OnPropertyChanged("Item[]");
182        OnPropertyChanged("Count");
183      }
184    }
185
186    public void Insert(int index, T item) {
187      int capacity = list.Capacity;
188      list.Insert(index, item);
189      OnItemsAdded(new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
190      OnItemsAdded(new T[] { item });
191      if (list.Capacity != capacity)
192        OnPropertyChanged("Capacity");
193      OnPropertyChanged("Item[]");
194      OnPropertyChanged("Count");
195    }
196    public void InsertRange(int index, IEnumerable<T> collection) {
197      int capacity = list.Capacity;
198      list.InsertRange(index, collection);
199      List<IndexedItem<T>> items = new List<IndexedItem<T>>();
200      foreach (T item in collection) {
201        items.Add(new IndexedItem<T>(index, item));
202        index++;
203      }
204      if (items.Count > 0) {
205        OnItemsAdded(items);
206        OnItemsAdded(collection);
207        if (list.Capacity != capacity)
208          OnPropertyChanged("Capacity");
209        OnPropertyChanged("Item[]");
210        OnPropertyChanged("Count");
211      }
212    }
213
214    /// <summary>
215    /// Performs a Clear and an AddRange, but does not fire separate events for those operations
216    /// </summary>
217    /// <param name="collection"></param>
218    public void Replace(IEnumerable<T> collection) {
219      List<IndexedItem<T>> oldItems = null;
220      if (list.Any()) oldItems = list.Select((x, i) => new IndexedItem<T>(i, x)).ToList();
221      else oldItems = new List<IndexedItem<T>>();
222
223      int oldCapacity = list.Capacity;
224      list.Clear();
225      list.AddRange(collection);
226
227      List<IndexedItem<T>> items = null;
228      if (list.Any()) items = list.Select((x, i) => new IndexedItem<T>(i, x)).ToList();
229      else items = new List<IndexedItem<T>>();
230
231      OnItemsReplaced(items, oldItems);
232      if (oldCapacity != list.Capacity) OnPropertyChanged("Capacity");
233      OnPropertyChanged("Item[]");
234      if (oldItems.Count != items.Count) OnPropertyChanged("Count");
235    }
236
237    public bool Remove(T item) {
238      int index = list.IndexOf(item);
239      if (index != -1) {
240        list.RemoveAt(index);
241        OnItemsRemoved(new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
242        OnItemsRemoved(new T[] { item });
243        OnPropertyChanged("Item[]");
244        OnPropertyChanged("Count");
245        return true;
246      }
247      return false;
248    }
249    public int RemoveAll(Predicate<T> match) {
250      if (match == null) throw new ArgumentNullException();
251      List<IndexedItem<T>> indexedItems = new List<IndexedItem<T>>();
252      List<T> items = new List<T>();
253      for (int i = 0; i < list.Count; i++) {
254        if (match(list[i])) {
255          indexedItems.Add(new IndexedItem<T>(i, list[i]));
256          items.Add(list[i]);
257        }
258      }
259      int result = 0;
260      if (indexedItems.Count > 0) {
261        result = list.RemoveAll(match);
262        OnItemsRemoved(indexedItems);
263        OnItemsRemoved(items);
264        OnPropertyChanged("Item[]");
265        OnPropertyChanged("Count");
266      }
267      return result;
268    }
269    public void RemoveAt(int index) {
270      T item = list[index];
271      list.RemoveAt(index);
272      OnItemsRemoved(new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
273      OnItemsRemoved(new T[] { item });
274      OnPropertyChanged("Item[]");
275      OnPropertyChanged("Count");
276    }
277    public void RemoveRange(int index, int count) {
278      if (count > 0) {
279        IndexedItem<T>[] indexedItems = GetIndexedItems(index, count);
280        T[] items = new T[count];
281        list.CopyTo(index, items, 0, count);
282        list.RemoveRange(index, count);
283        OnItemsRemoved(indexedItems);
284        OnItemsRemoved(items);
285        OnPropertyChanged("Item[]");
286        OnPropertyChanged("Count");
287      }
288    }
289
290    public void Clear() {
291      if (list.Count > 0) {
292        IndexedItem<T>[] indexedItems = GetIndexedItems();
293        T[] items = list.ToArray();
294        list.Clear();
295        OnCollectionReset(new IndexedItem<T>[0], indexedItems);
296        OnCollectionReset(new T[0], items);
297        OnPropertyChanged("Item[]");
298        OnPropertyChanged("Count");
299      }
300    }
301
302    public void Reverse() {
303      if (list.Count > 1) {
304        IndexedItem<T>[] oldItems = GetIndexedItems();
305        list.Reverse();
306        OnItemsMoved(GetIndexedItems(), oldItems);
307        OnPropertyChanged("Item[]");
308      }
309    }
310    public void Reverse(int index, int count) {
311      if (count > 1) {
312        IndexedItem<T>[] oldItems = GetIndexedItems(index, count);
313        list.Reverse(index, count);
314        OnItemsMoved(GetIndexedItems(index, count), oldItems);
315        OnPropertyChanged("Item[]");
316      }
317    }
318
319    public void Sort() {
320      if (list.Count > 1) {
321        IndexedItem<T>[] oldItems = GetIndexedItems();
322        list.Sort();
323        OnItemsMoved(GetIndexedItems(), oldItems);
324        OnPropertyChanged("Item[]");
325      }
326    }
327    public void Sort(Comparison<T> comparison) {
328      if (list.Count > 1) {
329        IndexedItem<T>[] oldItems = GetIndexedItems();
330        list.Sort(comparison);
331        OnItemsMoved(GetIndexedItems(), oldItems);
332        OnPropertyChanged("Item[]");
333      }
334    }
335    public void Sort(IComparer<T> comparer) {
336      if (list.Count > 1) {
337        IndexedItem<T>[] oldItems = GetIndexedItems();
338        list.Sort(comparer);
339        OnItemsMoved(GetIndexedItems(), oldItems);
340        OnPropertyChanged("Item[]");
341      }
342    }
343    public void Sort(int index, int count, IComparer<T> comparer) {
344      if (count > 1) {
345        IndexedItem<T>[] oldItems = GetIndexedItems(index, count);
346        list.Sort(index, count, comparer);
347        OnItemsMoved(GetIndexedItems(index, count), oldItems);
348        OnPropertyChanged("Item[]");
349      }
350    }
351    #endregion
352
353    #region Conversion
354    public ReadOnlyObservableList<T> AsReadOnly() {
355      return new ReadOnlyObservableList<T>(this);
356    }
357
358    public T[] ToArray() {
359      return list.ToArray();
360    }
361    public void CopyTo(T[] array) {
362      list.CopyTo(array);
363    }
364    public void CopyTo(T[] array, int arrayIndex) {
365      list.CopyTo(array, arrayIndex);
366    }
367    public void CopyTo(int index, T[] array, int arrayIndex, int count) {
368      list.CopyTo(index, array, arrayIndex, count);
369    }
370    public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter) {
371      return list.ConvertAll<TOutput>(converter);
372    }
373    #endregion
374
375    #region Processing
376    public void ForEach(Action<T> action) {
377      list.ForEach(action);
378    }
379    public bool TrueForAll(Predicate<T> match) {
380      return list.TrueForAll(match);
381    }
382    #endregion
383
384    #region Enumeration
385    public IEnumerator<T> GetEnumerator() {
386      return list.GetEnumerator();
387    }
388    IEnumerator IEnumerable.GetEnumerator() {
389      return list.GetEnumerator();
390    }
391    #endregion
392
393    #region Helpers
394    public void TrimExcess() {
395      int capacity = list.Capacity;
396      list.TrimExcess();
397      if (list.Capacity != capacity)
398        OnPropertyChanged("Capacity");
399    }
400    #endregion
401
402    #region Events
403    [field: NonSerialized]
404    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsAdded;
405    protected virtual void OnItemsAdded(IEnumerable<IndexedItem<T>> items) {
406      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = ItemsAdded;
407      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items));
408    }
409
410    [field: NonSerialized]
411    private event CollectionItemsChangedEventHandler<T> itemsAdded;
412    event CollectionItemsChangedEventHandler<T> INotifyObservableCollectionItemsChanged<T>.ItemsAdded {
413      add { itemsAdded += value; }
414      remove { itemsAdded -= value; }
415    }
416    private void OnItemsAdded(IEnumerable<T> items) {
417      CollectionItemsChangedEventHandler<T> handler = itemsAdded;
418      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<T>(items));
419    }
420
421    [field: NonSerialized]
422    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsRemoved;
423    protected virtual void OnItemsRemoved(IEnumerable<IndexedItem<T>> items) {
424      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = ItemsRemoved;
425      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items));
426    }
427
428    [field: NonSerialized]
429    private event CollectionItemsChangedEventHandler<T> itemsRemoved;
430    event CollectionItemsChangedEventHandler<T> INotifyObservableCollectionItemsChanged<T>.ItemsRemoved {
431      add { itemsRemoved += value; }
432      remove { itemsRemoved -= value; }
433    }
434    private void OnItemsRemoved(IEnumerable<T> items) {
435      CollectionItemsChangedEventHandler<T> handler = itemsRemoved;
436      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<T>(items));
437    }
438
439    [field: NonSerialized]
440    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsReplaced;
441    protected virtual void OnItemsReplaced(IEnumerable<IndexedItem<T>> items, IEnumerable<IndexedItem<T>> oldItems) {
442      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = ItemsReplaced;
443      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
444    }
445
446    [field: NonSerialized]
447    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsMoved;
448    protected virtual void OnItemsMoved(IEnumerable<IndexedItem<T>> items, IEnumerable<IndexedItem<T>> oldItems) {
449      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = ItemsMoved;
450      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
451    }
452
453    [field: NonSerialized]
454    public event CollectionItemsChangedEventHandler<IndexedItem<T>> CollectionReset;
455    protected virtual void OnCollectionReset(IEnumerable<IndexedItem<T>> items, IEnumerable<IndexedItem<T>> oldItems) {
456      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = CollectionReset;
457      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
458    }
459
460    [field: NonSerialized]
461    private event CollectionItemsChangedEventHandler<T> collectionReset;
462    event CollectionItemsChangedEventHandler<T> INotifyObservableCollectionItemsChanged<T>.CollectionReset {
463      add { collectionReset += value; }
464      remove { collectionReset -= value; }
465    }
466    private void OnCollectionReset(IEnumerable<T> items, IEnumerable<T> oldItems) {
467      CollectionItemsChangedEventHandler<T> handler = collectionReset;
468      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<T>(items, oldItems));
469    }
470
471    [field: NonSerialized]
472    public event PropertyChangedEventHandler PropertyChanged;
473    protected virtual void OnPropertyChanged(string propertyName) {
474      PropertyChangedEventHandler handler = PropertyChanged;
475      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
476    }
477    #endregion
478
479    #region Private helpers
480    private IndexedItem<T>[] GetIndexedItems() {
481      IndexedItem<T>[] items = new IndexedItem<T>[list.Count];
482      for (int i = 0; i < list.Count; i++)
483        items[i] = new IndexedItem<T>(i, list[i]);
484      return items;
485    }
486    private IndexedItem<T>[] GetIndexedItems(int index, int count) {
487      IndexedItem<T>[] items = new IndexedItem<T>[count];
488      for (int i = 0; i < count; i++)
489        items[i] = new IndexedItem<T>(index + i, list[index + i]);
490      return items;
491    }
492    #endregion
493  }
494}
Note: See TracBrowser for help on using the repository browser.