wasSharp – Diff between revs 44 and 54
?pathlinks?
Rev 44 | Rev 54 | |||
---|---|---|---|---|
Line 1... | Line 1... | |||
1 | /////////////////////////////////////////////////////////////////////////// |
1 | /////////////////////////////////////////////////////////////////////////// |
|
2 | // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
2 | // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
|
3 | // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
3 | // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
|
4 | // rights of fair usage, the disclaimer and warranty conditions. // |
4 | // rights of fair usage, the disclaimer and warranty conditions. // |
|
5 | /////////////////////////////////////////////////////////////////////////// |
5 | /////////////////////////////////////////////////////////////////////////// |
|
- | 6 | /// From https://gist.github.com/kzu/cfe3cb6e4fe3efea6d24 |
||
Line -... | Line 7... | |||
- | 7 | |
||
6 | |
8 | using System; |
|
7 | using System.Collections; |
9 | using System.Collections; |
|
8 | using System.Collections.Generic; |
10 | using System.Collections.Generic; |
|
- | 11 | using System.Collections.Specialized; |
||
- | 12 | using System.ComponentModel; |
||
- | 13 | using System.Diagnostics; |
||
- | 14 | using System.Dynamic; |
||
- | 15 | using System.Linq; |
||
9 | using System.Collections.Specialized; |
16 | using System.Text; |
|
Line 10... | Line 17... | |||
10 | using System.Threading; |
17 | using System.Threading.Tasks; |
|
11 | |
18 | |
|
12 | namespace wasSharp.Collections.Specialized |
- | ||
13 | { |
- | ||
14 | /////////////////////////////////////////////////////////////////////////// |
- | ||
15 | // Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
19 | namespace wasSharp.Collections.Specialized |
|
16 | /////////////////////////////////////////////////////////////////////////// |
20 | { |
|
17 | /// <summary> |
21 | /// <summary> |
|
18 | /// An implementation of an observable Dictionary. |
22 | /// Provides a dictionary for use with data binding. |
|
19 | /// </summary> |
23 | /// </summary> |
|
- | 24 | /// <typeparam name="TKey">Specifies the type of the keys in this collection.</typeparam> |
||
20 | /// <typeparam name="K">the key type</typeparam> |
25 | /// <typeparam name="TValue">Specifies the type of the values in this collection.</typeparam> |
|
- | 26 | [DebuggerDisplay("Count={Count}")] |
||
- | 27 | public class ObservableDictionary<TKey, TValue> : |
||
21 | /// <typeparam name="V">the value type</typeparam> |
28 | ICollection<KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue>, |
|
22 | public class ObservableDictionary<K, V> : IDictionary<K, V>, INotifyCollectionChanged |
- | ||
23 | { |
29 | INotifyCollectionChanged, INotifyPropertyChanged |
|
Line -... | Line 30... | |||
- | 30 | { |
||
24 | private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); |
31 | readonly IDictionary<TKey, TValue> dictionary; |
|
Line 25... | Line -... | |||
25 | private readonly Dictionary<K, V> store = new Dictionary<K, V>(); |
- | ||
26 | |
- | ||
27 | public bool IsVirgin { get; private set; } = true; |
- | ||
28 | |
- | ||
29 | public V this[K key] |
- | ||
30 | { |
- | ||
31 | get |
- | ||
32 | { |
32 | |
|
33 | _lock.EnterReadLock(); |
- | ||
34 | try |
- | ||
35 | { |
- | ||
36 | return store[key]; |
33 | /// <summary>Event raised when the collection changes.</summary> |
|
37 | } |
- | ||
38 | finally |
- | ||
Line 39... | Line 34... | |||
39 | { |
34 | public event NotifyCollectionChangedEventHandler CollectionChanged = (sender, args) => { }; |
|
40 | if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
- | ||
41 | } |
35 | |
|
42 | } |
36 | /// <summary>Event raised when a property on the collection changes.</summary> |
|
43 | |
- | ||
44 | set |
37 | public event PropertyChangedEventHandler PropertyChanged = (sender, args) => { }; |
|
45 | { |
- | ||
46 | _lock.EnterWriteLock(); |
38 | |
|
47 | try |
39 | /// <summary> |
|
48 | { |
- | ||
49 | store[key] = value; |
- | ||
50 | } |
40 | /// Initializes an instance of the class. |
|
51 | finally |
- | ||
52 | { |
- | ||
53 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
- | ||
Line 54... | Line -... | |||
54 | } |
- | ||
55 | } |
- | ||
56 | } |
- | ||
57 | |
- | ||
58 | public int Count => store.Count; |
41 | /// </summary> |
|
59 | |
- | ||
60 | public bool IsReadOnly => false; |
42 | public ObservableDictionary() |
|
61 | |
43 | : this(new Dictionary<TKey, TValue>()) |
|
62 | public ICollection<K> Keys |
44 | { |
|
63 | { |
45 | } |
|
64 | get |
- | ||
65 | { |
- | ||
66 | _lock.EnterReadLock(); |
46 | |
|
67 | try |
47 | /// <summary> |
|
68 | { |
- | ||
69 | return store.Keys; |
- | ||
70 | } |
48 | /// Initializes an instance of the class using another dictionary as |
|
Line 71... | Line 49... | |||
71 | finally |
49 | /// the key/value store. |
|
72 | { |
50 | /// </summary> |
|
73 | if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
- | ||
74 | } |
- | ||
75 | } |
- | ||
76 | } |
- | ||
77 | |
- | ||
78 | public ICollection<V> Values |
51 | public ObservableDictionary(IDictionary<TKey, TValue> dictionary) |
|
79 | { |
- | ||
80 | get |
- | ||
81 | { |
- | ||
82 | _lock.EnterReadLock(); |
- | ||
83 | try |
- | ||
84 | { |
- | ||
85 | return store.Values; |
52 | { |
|
Line 86... | Line 53... | |||
86 | } |
53 | this.dictionary = dictionary; |
|
87 | finally |
- | ||
88 | { |
- | ||
89 | if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
- | ||
90 | } |
54 | } |
|
91 | } |
55 | |
|
92 | } |
56 | void AddWithNotification(KeyValuePair<TKey, TValue> item) |
|
93 | |
57 | { |
|
94 | public void Add(KeyValuePair<K, V> item) |
58 | AddWithNotification(item.Key, item.Value); |
|
95 | { |
59 | } |
|
96 | _lock.EnterWriteLock(); |
- | ||
97 | try |
60 | |
|
98 | { |
61 | void AddWithNotification(TKey key, TValue value) |
|
99 | ((IDictionary<K, V>) store).Add(item); |
62 | { |
|
Line 100... | Line 63... | |||
100 | } |
63 | dictionary.Add(key, value); |
|
101 | finally |
- | ||
102 | { |
- | ||
103 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
- | ||
104 | } |
64 | |
|
105 | IsVirgin = false; |
65 | CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, |
|
106 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); |
- | ||
107 | } |
66 | new KeyValuePair<TKey, TValue>(key, value))); |
|
108 | |
67 | PropertyChanged(this, new PropertyChangedEventArgs("Count")); |
|
- | 68 | PropertyChanged(this, new PropertyChangedEventArgs("Keys")); |
||
109 | public void Add(K key, V value) |
69 | PropertyChanged(this, new PropertyChangedEventArgs("Values")); |
|
- | 70 | } |
||
- | 71 | |
||
- | 72 | bool RemoveWithNotification(TKey key) |
||
- | 73 | { |
||
- | 74 | TValue value; |
||
110 | { |
75 | if (dictionary.TryGetValue(key, out value) && dictionary.Remove(key)) |
|
- | 76 | { |
||
111 | _lock.EnterWriteLock(); |
77 | CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, |
|
112 | try |
- | ||
113 | { |
- | ||
114 | store.Add(key, value); |
78 | new KeyValuePair<TKey, TValue>(key, value))); |
|
Line 115... | Line 79... | |||
115 | } |
79 | PropertyChanged(this, new PropertyChangedEventArgs("Count")); |
|
116 | finally |
80 | PropertyChanged(this, new PropertyChangedEventArgs("Keys")); |
|
117 | { |
- | ||
118 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
- | ||
119 | } |
- | ||
120 | IsVirgin = false; |
81 | PropertyChanged(this, new PropertyChangedEventArgs("Values")); |
|
121 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, |
- | ||
122 | new KeyValuePair<K, V>(key, value))); |
- | ||
123 | } |
82 | |
|
124 | |
83 | return true; |
|
125 | public void Clear() |
- | ||
126 | { |
84 | } |
|
127 | _lock.EnterWriteLock(); |
85 | |
|
128 | try |
86 | return false; |
|
129 | { |
87 | } |
|
Line 130... | Line 88... | |||
130 | store.Clear(); |
88 | |
|
131 | } |
89 | public void Clear() |
|
132 | finally |
90 | { |
|
133 | { |
91 | dictionary.Clear(); |
|
134 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
92 | |
|
- | 93 | CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); |
||
- | 94 | PropertyChanged(this, new PropertyChangedEventArgs("Count")); |
||
- | 95 | PropertyChanged(this, new PropertyChangedEventArgs("Keys")); |
||
- | 96 | PropertyChanged(this, new PropertyChangedEventArgs("Values")); |
||
135 | } |
97 | } |
|
- | 98 | |
||
136 | if (!IsVirgin) |
99 | void UpdateWithNotification(TKey key, TValue value) |
|
137 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); |
100 | { |
|
138 | IsVirgin = false; |
101 | TValue existing; |
|
139 | } |
102 | if (dictionary.TryGetValue(key, out existing)) |
|
140 | |
103 | { |
|
141 | public bool Contains(KeyValuePair<K, V> item) |
104 | dictionary[key] = value; |
|
Line 142... | Line -... | |||
142 | { |
- | ||
143 | _lock.EnterReadLock(); |
105 | |
|
144 | try |
106 | CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, |
|
145 | { |
107 | new KeyValuePair<TKey, TValue>(key, value), |
|
- | 108 | new KeyValuePair<TKey, TValue>(key, existing))); |
||
146 | return ((IDictionary<K, V>) store).Contains(item); |
109 | PropertyChanged(this, new PropertyChangedEventArgs("Values")); |
|
147 | } |
110 | } |
|
148 | finally |
111 | else |
|
- | 112 | { |
||
- | 113 | AddWithNotification(key, value); |
||
- | 114 | } |
||
149 | { |
115 | } |
|
- | 116 | |
||
- | 117 | /// <summary> |
||
- | 118 | /// Allows derived classes to raise custom property changed events. |
||
- | 119 | /// </summary> |
||
- | 120 | protected void RaisePropertyChanged(PropertyChangedEventArgs args) |
||
150 | if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
121 | { |
|
151 | } |
122 | PropertyChanged(this, args); |
|
152 | } |
- | ||
153 | |
123 | } |
|
Line -... | Line 124... | |||
- | 124 | |
||
154 | public bool ContainsKey(K key) |
125 | #region IDictionary<TKey,TValue> Members |
|
155 | { |
126 | |
|
- | 127 | /// <summary> |
||
156 | _lock.EnterReadLock(); |
128 | /// Adds an element with the provided key and value to the <see cref="T:System.Collections.Generic.IDictionary`2" />. |
|
- | 129 | /// </summary> |
||
157 | try |
130 | /// <param name="key">The object to use as the key of the element to add.</param> |
|
- | 131 | /// <param name="value">The object to use as the value of the element to add.</param> |
||
158 | { |
132 | public void Add(TKey key, TValue value) |
|
159 | return store.ContainsKey(key); |
133 | { |
|
160 | } |
134 | AddWithNotification(key, value); |
|
- | 135 | } |
||
161 | finally |
136 | |
|
- | 137 | /// <summary> |
||
- | 138 | /// Determines whether the <see cref="T:System.Collections.Generic.IDictionary`2" /> contains an element with the specified key. |
||
- | 139 | /// </summary> |
||
- | 140 | /// <param name="key">The key to locate in the <see cref="T:System.Collections.Generic.IDictionary`2" />.</param> |
||
162 | { |
141 | /// <returns> |
|
163 | if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
142 | /// true if the <see cref="T:System.Collections.Generic.IDictionary`2" /> contains an element with the key; otherwise, false. |
|
164 | } |
- | ||
165 | } |
143 | /// </returns> |
|
Line -... | Line 144... | |||
- | 144 | public bool ContainsKey(TKey key) |
||
166 | |
145 | { |
|
167 | public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex) |
146 | return dictionary.ContainsKey(key); |
|
168 | { |
147 | } |
|
169 | _lock.EnterReadLock(); |
148 | |
|
- | 149 | /// <summary> |
||
170 | try |
150 | /// Gets an <see cref="T:System.Collections.Generic.ICollection`1" /> containing the keys of the <see cref="T:System.Collections.Generic.IDictionary`2" />. |
|
171 | { |
151 | /// </summary> |
|
172 | ((IDictionary<K, V>) store).CopyTo(array, arrayIndex); |
152 | /// <returns>An <see cref="T:System.Collections.Generic.ICollection`1" /> containing the keys of the object that implements <see cref="T:System.Collections.Generic.IDictionary`2" />.</returns> |
|
173 | } |
153 | public ICollection<TKey> Keys |
|
174 | finally |
- | ||
175 | { |
154 | { |
|
- | 155 | get { return dictionary.Keys; } |
||
- | 156 | } |
||
- | 157 | |
||
- | 158 | /// <summary> |
||
- | 159 | /// Removes the element with the specified key from the <see cref="T:System.Collections.Generic.IDictionary`2" />. |
||
176 | if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
160 | /// </summary> |
|
177 | } |
161 | /// <param name="key">The key of the element to remove.</param> |
|
- | 162 | /// <returns> |
||
- | 163 | /// true if the element is successfully removed; otherwise, false. This method also returns false if <paramref name="key" /> was not found in the original <see cref="T:System.Collections.Generic.IDictionary`2" />. |
||
- | 164 | /// </returns> |
||
178 | } |
165 | public bool Remove(TKey key) |
|
179 | |
166 | { |
|
180 | public IEnumerator<KeyValuePair<K, V>> GetEnumerator() |
- | ||
181 | { |
167 | return RemoveWithNotification(key); |
|
Line 182... | Line -... | |||
182 | _lock.EnterReadLock(); |
- | ||
183 | try |
168 | } |
|
184 | { |
169 | |
|
185 | using (var enumerator = ((IDictionary<K, V>)store).GetEnumerator()) |
170 | /// <summary> |
|
- | 171 | /// Gets the value associated with the specified key. |
||
186 | { |
172 | /// </summary> |
|
187 | while (enumerator.MoveNext()) |
173 | /// <param name="key">The key whose value to get.</param> |
|
188 | yield return enumerator.Current; |
174 | /// <param name="value">When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the <paramref name="value" /> parameter. This parameter is passed uninitialized.</param> |
|
189 | } |
175 | /// <returns> |
|
- | 176 | /// true if the object that implements <see cref="T:System.Collections.Generic.IDictionary`2" /> contains an element with the specified key; otherwise, false. |
||
190 | } |
177 | /// </returns> |
|
- | 178 | public bool TryGetValue(TKey key, out TValue value) |
||
- | 179 | { |
||
- | 180 | return dictionary.TryGetValue(key, out value); |
||
- | 181 | } |
||
- | 182 | |
||
191 | finally |
183 | /// <summary> |
|
192 | { |
- | ||
193 | if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
- | ||
194 | } |
184 | /// Gets an <see cref="T:System.Collections.Generic.ICollection`1" /> containing the values in the <see cref="T:System.Collections.Generic.IDictionary`2" />. |
|
195 | } |
- | ||
196 | |
- | ||
197 | public bool Remove(KeyValuePair<K, V> item) |
185 | /// </summary> |
|
198 | { |
186 | /// <returns>An <see cref="T:System.Collections.Generic.ICollection`1" /> containing the values in the object that implements <see cref="T:System.Collections.Generic.IDictionary`2" />.</returns> |
|
Line 199... | Line -... | |||
199 | _lock.EnterWriteLock(); |
- | ||
200 | bool removed; |
- | ||
201 | try |
- | ||
202 | { |
- | ||
203 | removed = ((IDictionary<K, V>) store).Remove(item); |
- | ||
204 | } |
187 | public ICollection<TValue> Values |
|
205 | finally |
- | ||
206 | { |
- | ||
207 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
- | ||
Line 208... | Line -... | |||
208 | } |
- | ||
209 | IsVirgin = false; |
- | ||
210 | if (removed) |
- | ||
211 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item)); |
- | ||
212 | return removed; |
188 | { |
|
213 | } |
- | ||
214 | |
- | ||
215 | public bool Remove(K key) |
- | ||
216 | { |
- | ||
217 | KeyValuePair<K, V> item; |
- | ||
218 | _lock.EnterWriteLock(); |
- | ||
Line 219... | Line 189... | |||
219 | bool removed; |
189 | get { return dictionary.Values; } |
|
220 | try |
190 | } |
|
221 | { |
191 | |
|
222 | if (store.ContainsKey(key)) |
- | ||
223 | item = new KeyValuePair<K, V>(key, store[key]); |
- | ||
224 | |
- | ||
225 | removed = store.Remove(key); |
- | ||
226 | } |
- | ||
227 | finally |
- | ||
228 | { |
- | ||
229 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
- | ||
230 | } |
192 | /// <summary> |
|
Line 231... | Line 193... | |||
231 | IsVirgin = false; |
193 | /// Gets or sets the element with the specified key. |
|
232 | if (removed) |
- | ||
233 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item)); |
- | ||
234 | return removed; |
- | ||
235 | } |
- | ||
236 | |
- | ||
237 | public bool TryGetValue(K key, out V value) |
194 | /// </summary> |
|
238 | { |
195 | /// <param name="key">The key.</param> |
|
- | 196 | /// <returns></returns> |
||
- | 197 | public TValue this[TKey key] |
||
239 | _lock.EnterReadLock(); |
198 | { |
|
240 | try |
199 | get { return dictionary[key]; } |
|
- | 200 | set { UpdateWithNotification(key, value); } |
||
241 | { |
201 | } |
|
- | 202 | |
||
- | 203 | #endregion |
||
242 | return store.TryGetValue(key, out value); |
204 | |
|
- | 205 | #region ICollection<KeyValuePair<TKey,TValue>> Members |
||
- | 206 | |
||
243 | } |
207 | void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) |
|
244 | finally |
208 | { |
|
245 | { |
- | ||
246 | if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
209 | AddWithNotification(item); |
|
Line 247... | Line 210... | |||
247 | } |
210 | } |
|
- | 211 | |
||
- | 212 | void ICollection<KeyValuePair<TKey, TValue>>.Clear() |
||
- | 213 | { |
||
- | 214 | dictionary.Clear(); |
||
- | 215 | |
||
- | 216 | CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); |
||
- | 217 | PropertyChanged(this, new PropertyChangedEventArgs("Count")); |
||
- | 218 | PropertyChanged(this, new PropertyChangedEventArgs("Keys")); |
||
- | 219 | PropertyChanged(this, new PropertyChangedEventArgs("Values")); |
||
- | 220 | } |
||
- | 221 | |
||
- | 222 | bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) => |
||
- | 223 | dictionary.Contains(item); |
||
- | 224 | |
||
- | 225 | void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) |
||
- | 226 | { |
||
- | 227 | dictionary.CopyTo(array, arrayIndex); |
||
- | 228 | } |
||
- | 229 | |
||
Line -... | Line 230... | |||
- | 230 | int ICollection<KeyValuePair<TKey, TValue>>.Count => |
||
248 | } |
231 | dictionary.Count(); |
|
249 | |
232 | |
|
250 | IEnumerator IEnumerable.GetEnumerator() |
233 | bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => |
|
251 | { |
234 | dictionary.IsReadOnly; |
|
- | 235 | |
||
252 | _lock.EnterReadLock(); |
236 | bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) => |
|
253 | try |
237 | RemoveWithNotification(item.Key); |