Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 9138 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
RevLine 
[2572]1#region License Information
2/* HeuristicLab
[7259]3 * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[2572]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;
[2620]25using System.ComponentModel;
[6342]26using System.Linq;
[3560]27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
[2572]28
29namespace HeuristicLab.Collections {
[3560]30  [StorableClass]
[2572]31  [Serializable]
[2574]32  public class ObservableList<T> : IObservableList<T> {
[3560]33    [Storable]
[3286]34    protected List<T> list;
[2572]35
36    #region Properties
37    public int Capacity {
38      get { return list.Capacity; }
[2620]39      set {
40        if (list.Capacity != value) {
41          list.Capacity = value;
42          OnPropertyChanged("Capacity");
43        }
44      }
[2572]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];
[2745]59        if (!((item == null) && (value == null)) && ((item == null) || (!item.Equals(value)))) {
[2620]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        }
[2572]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    }
[3560]78    [StorableConstructor]
79    protected ObservableList(bool deserializing) { }
[2572]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) {
[2620]158      int capacity = list.Capacity;
[2572]159      list.Add(item);
[8610]160      OnItemsAdded(new IndexedItem<T>[] { new IndexedItem<T>(list.Count - 1, item) });
161      OnItemsAdded(new T[] { item });
[2620]162      if (list.Capacity != capacity)
163        OnPropertyChanged("Capacity");
164      OnPropertyChanged("Item[]");
165      OnPropertyChanged("Count");
[2572]166    }
167    public void AddRange(IEnumerable<T> collection) {
[2620]168      int capacity = list.Capacity;
[2572]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      }
[2620]176      if (items.Count > 0) {
[8610]177        OnItemsAdded(items);
178        OnItemsAdded(collection);
[2620]179        if (list.Capacity != capacity)
180          OnPropertyChanged("Capacity");
181        OnPropertyChanged("Item[]");
182        OnPropertyChanged("Count");
183      }
[2572]184    }
185
186    public void Insert(int index, T item) {
[2620]187      int capacity = list.Capacity;
[2572]188      list.Insert(index, item);
[8610]189      OnItemsAdded(new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
190      OnItemsAdded(new T[] { item });
[2620]191      if (list.Capacity != capacity)
192        OnPropertyChanged("Capacity");
193      OnPropertyChanged("Item[]");
194      OnPropertyChanged("Count");
[2572]195    }
196    public void InsertRange(int index, IEnumerable<T> collection) {
[2620]197      int capacity = list.Capacity;
[2572]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      }
[2620]204      if (items.Count > 0) {
[8610]205        OnItemsAdded(items);
206        OnItemsAdded(collection);
[2620]207        if (list.Capacity != capacity)
208          OnPropertyChanged("Capacity");
209        OnPropertyChanged("Item[]");
210        OnPropertyChanged("Count");
211      }
[2572]212    }
213
[6342]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
[8610]231      OnItemsReplaced(items, oldItems);
[6342]232      if (oldCapacity != list.Capacity) OnPropertyChanged("Capacity");
233      OnPropertyChanged("Item[]");
234      if (oldItems.Count != items.Count) OnPropertyChanged("Count");
235    }
236
[2572]237    public bool Remove(T item) {
238      int index = list.IndexOf(item);
239      if (index != -1) {
240        list.RemoveAt(index);
[8610]241        OnItemsRemoved(new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
242        OnItemsRemoved(new T[] { item });
[2620]243        OnPropertyChanged("Item[]");
244        OnPropertyChanged("Count");
[2572]245        return true;
246      }
247      return false;
248    }
249    public int RemoveAll(Predicate<T> match) {
[2573]250      if (match == null) throw new ArgumentNullException();
[2623]251      List<IndexedItem<T>> indexedItems = new List<IndexedItem<T>>();
252      List<T> items = new List<T>();
[2572]253      for (int i = 0; i < list.Count; i++) {
[2623]254        if (match(list[i])) {
255          indexedItems.Add(new IndexedItem<T>(i, list[i]));
256          items.Add(list[i]);
257        }
[2572]258      }
[2620]259      int result = 0;
[2623]260      if (indexedItems.Count > 0) {
[2620]261        result = list.RemoveAll(match);
[8610]262        OnItemsRemoved(indexedItems);
263        OnItemsRemoved(items);
[2620]264        OnPropertyChanged("Item[]");
265        OnPropertyChanged("Count");
266      }
[2572]267      return result;
268    }
269    public void RemoveAt(int index) {
270      T item = list[index];
271      list.RemoveAt(index);
[8610]272      OnItemsRemoved(new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
273      OnItemsRemoved(new T[] { item });
[2620]274      OnPropertyChanged("Item[]");
275      OnPropertyChanged("Count");
[2572]276    }
277    public void RemoveRange(int index, int count) {
[2620]278      if (count > 0) {
[2623]279        IndexedItem<T>[] indexedItems = GetIndexedItems(index, count);
280        T[] items = new T[count];
281        list.CopyTo(index, items, 0, count);
[2620]282        list.RemoveRange(index, count);
[8610]283        OnItemsRemoved(indexedItems);
284        OnItemsRemoved(items);
[2620]285        OnPropertyChanged("Item[]");
286        OnPropertyChanged("Count");
287      }
[2572]288    }
289
290    public void Clear() {
[2620]291      if (list.Count > 0) {
[2623]292        IndexedItem<T>[] indexedItems = GetIndexedItems();
293        T[] items = list.ToArray();
[2620]294        list.Clear();
[8610]295        OnCollectionReset(new IndexedItem<T>[0], indexedItems);
296        OnCollectionReset(new T[0], items);
[2620]297        OnPropertyChanged("Item[]");
298        OnPropertyChanged("Count");
299      }
[2572]300    }
301
302    public void Reverse() {
[2620]303      if (list.Count > 1) {
304        IndexedItem<T>[] oldItems = GetIndexedItems();
305        list.Reverse();
[8610]306        OnItemsMoved(GetIndexedItems(), oldItems);
[2620]307        OnPropertyChanged("Item[]");
308      }
[2572]309    }
310    public void Reverse(int index, int count) {
[2620]311      if (count > 1) {
312        IndexedItem<T>[] oldItems = GetIndexedItems(index, count);
313        list.Reverse(index, count);
[8610]314        OnItemsMoved(GetIndexedItems(index, count), oldItems);
[2620]315        OnPropertyChanged("Item[]");
316      }
[2572]317    }
318
319    public void Sort() {
[2620]320      if (list.Count > 1) {
321        IndexedItem<T>[] oldItems = GetIndexedItems();
322        list.Sort();
[8610]323        OnItemsMoved(GetIndexedItems(), oldItems);
[2620]324        OnPropertyChanged("Item[]");
325      }
[2572]326    }
327    public void Sort(Comparison<T> comparison) {
[2620]328      if (list.Count > 1) {
329        IndexedItem<T>[] oldItems = GetIndexedItems();
330        list.Sort(comparison);
[8610]331        OnItemsMoved(GetIndexedItems(), oldItems);
[2620]332        OnPropertyChanged("Item[]");
333      }
[2572]334    }
335    public void Sort(IComparer<T> comparer) {
[2620]336      if (list.Count > 1) {
337        IndexedItem<T>[] oldItems = GetIndexedItems();
338        list.Sort(comparer);
[8610]339        OnItemsMoved(GetIndexedItems(), oldItems);
[2620]340        OnPropertyChanged("Item[]");
341      }
[2572]342    }
343    public void Sort(int index, int count, IComparer<T> comparer) {
[2745]344      if (count > 1) {
[2620]345        IndexedItem<T>[] oldItems = GetIndexedItems(index, count);
346        list.Sort(index, count, comparer);
[8610]347        OnItemsMoved(GetIndexedItems(index, count), oldItems);
[2620]348        OnPropertyChanged("Item[]");
349      }
[2572]350    }
351    #endregion
352
353    #region Conversion
[2618]354    public ReadOnlyObservableList<T> AsReadOnly() {
355      return new ReadOnlyObservableList<T>(this);
[2572]356    }
[8610]357
[2572]358    public T[] ToArray() {
359      return list.ToArray();
360    }
[2623]361    public void CopyTo(T[] array) {
362      list.CopyTo(array);
363    }
364    public void CopyTo(T[] array, int arrayIndex) {
[2572]365      list.CopyTo(array, arrayIndex);
366    }
[2623]367    public void CopyTo(int index, T[] array, int arrayIndex, int count) {
368      list.CopyTo(index, array, arrayIndex, count);
369    }
[2572]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
[2623]385    public IEnumerator<T> GetEnumerator() {
[2572]386      return list.GetEnumerator();
387    }
388    IEnumerator IEnumerable.GetEnumerator() {
[2623]389      return list.GetEnumerator();
[2572]390    }
391    #endregion
392
393    #region Helpers
394    public void TrimExcess() {
[2620]395      int capacity = list.Capacity;
[2572]396      list.TrimExcess();
[2620]397      if (list.Capacity != capacity)
398        OnPropertyChanged("Capacity");
[2572]399    }
400    #endregion
401
[2574]402    #region Events
403    [field: NonSerialized]
404    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsAdded;
405    protected virtual void OnItemsAdded(IEnumerable<IndexedItem<T>> items) {
[3317]406      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = ItemsAdded;
407      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items));
[2574]408    }
409
410    [field: NonSerialized]
[2623]411    private event CollectionItemsChangedEventHandler<T> itemsAdded;
[2832]412    event CollectionItemsChangedEventHandler<T> INotifyObservableCollectionItemsChanged<T>.ItemsAdded {
[2623]413      add { itemsAdded += value; }
414      remove { itemsAdded -= value; }
415    }
416    private void OnItemsAdded(IEnumerable<T> items) {
[3317]417      CollectionItemsChangedEventHandler<T> handler = itemsAdded;
418      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<T>(items));
[2623]419    }
420
421    [field: NonSerialized]
[2574]422    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsRemoved;
423    protected virtual void OnItemsRemoved(IEnumerable<IndexedItem<T>> items) {
[3317]424      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = ItemsRemoved;
425      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items));
[2574]426    }
427
428    [field: NonSerialized]
[2623]429    private event CollectionItemsChangedEventHandler<T> itemsRemoved;
[2832]430    event CollectionItemsChangedEventHandler<T> INotifyObservableCollectionItemsChanged<T>.ItemsRemoved {
[2623]431      add { itemsRemoved += value; }
432      remove { itemsRemoved -= value; }
433    }
434    private void OnItemsRemoved(IEnumerable<T> items) {
[3317]435      CollectionItemsChangedEventHandler<T> handler = itemsRemoved;
436      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<T>(items));
[2623]437    }
438
439    [field: NonSerialized]
[2574]440    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsReplaced;
441    protected virtual void OnItemsReplaced(IEnumerable<IndexedItem<T>> items, IEnumerable<IndexedItem<T>> oldItems) {
[3317]442      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = ItemsReplaced;
443      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
[2574]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) {
[3317]449      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = ItemsMoved;
450      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
[2574]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) {
[3317]456      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = CollectionReset;
457      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
[2574]458    }
[2620]459
460    [field: NonSerialized]
[2623]461    private event CollectionItemsChangedEventHandler<T> collectionReset;
[2832]462    event CollectionItemsChangedEventHandler<T> INotifyObservableCollectionItemsChanged<T>.CollectionReset {
[2623]463      add { collectionReset += value; }
464      remove { collectionReset -= value; }
465    }
466    private void OnCollectionReset(IEnumerable<T> items, IEnumerable<T> oldItems) {
[3317]467      CollectionItemsChangedEventHandler<T> handler = collectionReset;
468      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<T>(items, oldItems));
[2623]469    }
470
471    [field: NonSerialized]
[2620]472    public event PropertyChangedEventHandler PropertyChanged;
473    protected virtual void OnPropertyChanged(string propertyName) {
[3317]474      PropertyChangedEventHandler handler = PropertyChanged;
475      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
[2620]476    }
[2574]477    #endregion
478
[2572]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.