Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Collections/3.3/ObservableKeyedList.cs @ 16607

Last change on this file since 16607 was 15584, checked in by swagner, 7 years ago

#2640: Updated year of copyrights in license headers on stable

File size: 6.1 KB
RevLine 
[8610]1#region License Information
2
3/* HeuristicLab
[15584]4 * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[8610]5 *
6 * This file is part of HeuristicLab.
7 *
8 * HeuristicLab is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * HeuristicLab is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#endregion
23
24using System;
25using System.Collections.Generic;
26using System.Linq;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28
29namespace HeuristicLab.Collections {
30  [Serializable]
31  [StorableClass]
32  public abstract class ObservableKeyedList<TKey, TItem> : ObservableList<TItem>, IObservableKeyedList<TKey, TItem> {
33
34    private Dictionary<TKey, TItem> dict;
35    [Storable]
36    protected Dictionary<TKey, TItem> Dictionary {
37      get { return dict; }
38      private set { dict = value; }
39    }
40    protected IEqualityComparer<TKey> Comparer {
41      get { return dict.Comparer; }
42    }
43
44    public TItem this[TKey key] {
45      get { return dict[key]; }
46    }
47
48    #region constructors
49    protected ObservableKeyedList()
50      : base() {
51      dict = new Dictionary<TKey, TItem>();
52    }
53    protected ObservableKeyedList(int capacity)
54      : base(capacity) {
55      dict = new Dictionary<TKey, TItem>(capacity);
56    }
57    protected ObservableKeyedList(IEqualityComparer<TKey> comparer)
58      : base() {
59      dict = new Dictionary<TKey, TItem>(comparer);
60    }
61    protected ObservableKeyedList(int capacity, IEqualityComparer<TKey> comparer)
62      : base(capacity) {
63      dict = new Dictionary<TKey, TItem>(capacity, comparer);
64    }
65    [StorableConstructor]
66    protected ObservableKeyedList(bool deserializing) : base(deserializing) { }
67    #endregion
68
69    protected abstract TKey GetKeyForItem(TItem item);
70    protected void UpdateItemKey(TItem item) {
71      if (item == null) throw new ArgumentNullException();
72      var dictionaryItem = dict.FirstOrDefault(i => i.Value.Equals(item));
73      if (dictionaryItem.Equals(default(KeyValuePair<TKey, TItem>))) throw new ArgumentException("Item not found");
74
75      dict.Remove(dictionaryItem.Key);
76      dict.Add(GetKeyForItem(item), item);
77      int index = IndexOf(item);
78      OnItemsReplaced(new[] { new IndexedItem<TItem>(index, item) }, new[] { new IndexedItem<TItem>(index, item) });
79      OnItemsReplaced(new[] { item }, new[] { item });
80      OnPropertyChanged("Item[]");
81    }
82
83    #region methods
84    public new ReadOnlyObservableKeyedList<TKey, TItem> AsReadOnly() {
85      return new ReadOnlyObservableKeyedList<TKey, TItem>(this);
86    }
87
88    public bool ContainsKey(TKey key) {
89      return dict.ContainsKey(key);
90    }
91    public new bool Contains(TItem item) {
92      TKey key = GetKeyForItem(item);
93      return ContainsKey(key);
94    }
95
96    public bool TryGetValue(TKey key, out TItem item) {
97      return dict.TryGetValue(key, out item);
98    }
99
100    public bool Remove(TKey key) {
101      TItem item;
102      if (!TryGetValue(key, out item)) return false;
103      return base.Remove(item);
104    }
105    #endregion
106
107
108    #region Events
109    [field: NonSerialized]
110    private event CollectionItemsChangedEventHandler<TItem> itemsReplaced;
111    event CollectionItemsChangedEventHandler<TItem> INotifyObservableKeyedCollectionItemsChanged<TKey, TItem>.ItemsReplaced {
112      add { itemsReplaced += value; }
113      remove { itemsReplaced -= value; }
114    }
115    private void OnItemsReplaced(IEnumerable<TItem> items, IEnumerable<TItem> oldItems) {
116      var handler = itemsReplaced;
117      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<TItem>(items, oldItems));
118    }
119
120    protected override void OnItemsAdded(IEnumerable<IndexedItem<TItem>> items) {
121      UpdateDictionary(items, Enumerable.Empty<IndexedItem<TItem>>());
122      base.OnItemsAdded(items);
123    }
124
125    protected override void OnItemsRemoved(IEnumerable<IndexedItem<TItem>> items) {
126      UpdateDictionary(Enumerable.Empty<IndexedItem<TItem>>(), items);
127      base.OnItemsRemoved(items);
128    }
129
130    protected override void OnItemsReplaced(IEnumerable<IndexedItem<TItem>> items, IEnumerable<IndexedItem<TItem>> oldItems) {
131      UpdateDictionary(items, oldItems);
132      base.OnItemsReplaced(items, oldItems);
133    }
134
135    protected override void OnCollectionReset(IEnumerable<IndexedItem<TItem>> items, IEnumerable<IndexedItem<TItem>> oldItems) {
136      UpdateDictionary(items, oldItems);
137      base.OnCollectionReset(items, oldItems);
138    }
139    #endregion
140
141    #region helper methods
142    private void UpdateDictionary(IEnumerable<IndexedItem<TItem>> items, IEnumerable<IndexedItem<TItem>> oldItems) {
143      foreach (var item in oldItems)
144        dict.Remove(GetKeyForItem(item.Value));
145
146      bool duplicateKeyFound = false;
147      foreach (var item in items) {
148        TKey key = GetKeyForItem(item.Value);
149        if (dict.ContainsKey(key)) {
150          duplicateKeyFound = true;
151          break;
152        }
153        dict.Add(key, item.Value);
154      }
155
156      //restore old state of list and dictionary
157      if (duplicateKeyFound) {
158        foreach (var item in items.OrderByDescending(i => i.Index)) {
159          list.RemoveAt(item.Index);
160        }
161        foreach (var item in items.Select(i => i.Value).Except(list)) {
162          TKey key = GetKeyForItem(item);
163          dict.Remove(key);
164        }
165        foreach (var item in oldItems.OrderByDescending(i => i.Index)) {
166          list.Insert(item.Index, item.Value);
167          TKey key = GetKeyForItem(item.Value);
168          dict.Add(key, item.Value);
169        }
170        throw new ArgumentException("An element with the same key already exists.");
171      }
172    }
173    #endregion
174  }
175}
Note: See TracBrowser for help on using the repository browser.