wasSharp – Diff between revs 44 and 54

Subversion Repositories:
Rev:
Show entire fileRegard whitespace
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);