1+ namespace Hexa . NET . Utilities . Collections
2+ {
3+ using System . Collections . Generic ;
4+ using System . Collections . ObjectModel ;
5+
6+ /// <summary>
7+ /// Represents an observable dictionary that allows you to observe changes to its contents.
8+ /// </summary>
9+ [ Serializable ]
10+ public class ObservableDictionary < TKey , TValue > : ObservableCollection < ObservableKeyValuePair < TKey , TValue > > , IDictionary < TKey , TValue > where TKey : notnull
11+ {
12+ /// <summary>
13+ /// Initializes a new instance of the <see cref="ObservableDictionary{TKey, TValue}"/> class.
14+ /// </summary>
15+ public ObservableDictionary ( )
16+ {
17+ }
18+
19+ /// <summary>
20+ /// Initializes a new instance of the <see cref="ObservableDictionary{TKey, TValue}"/> class with an existing collection.
21+ /// </summary>
22+ /// <param name="collection">An existing collection of key-value pairs.</param>
23+ public ObservableDictionary ( IEnumerable < ObservableKeyValuePair < TKey , TValue > > collection ) : base ( collection )
24+ {
25+ }
26+
27+ /// <summary>
28+ /// Initializes a new instance of the <see cref="ObservableDictionary{TKey, TValue}"/> class with an existing list.
29+ /// </summary>
30+ /// <param name="list">An existing list of key-value pairs.</param>
31+ public ObservableDictionary ( List < ObservableKeyValuePair < TKey , TValue > > list ) : base ( list )
32+ {
33+ }
34+
35+ /// <summary>
36+ /// Adds a key-value pair to the dictionary.
37+ /// </summary>
38+ /// <param name="key">The key to add.</param>
39+ /// <param name="value">The value associated with the key.</param>
40+ public virtual void Add ( TKey key , TValue value )
41+ {
42+ if ( ContainsKey ( key ) )
43+ {
44+ throw new ArgumentException ( "The dictionary already contains the key" ) ;
45+ }
46+ Add ( new ObservableKeyValuePair < TKey , TValue > ( ) { Key = key , Value = value } ) ;
47+ }
48+
49+ /// <summary>
50+ /// Determines whether the dictionary contains the specified key.
51+ /// </summary>
52+ /// <param name="key">The key to check for.</param>
53+ /// <returns><c>true</c> if the dictionary contains the key; otherwise, <c>false</c>.</returns>
54+ public virtual bool ContainsKey ( TKey key )
55+ {
56+ var r = ThisAsCollection ( ) . FirstOrDefault ( ( i ) => ObservableDictionary < TKey , TValue > . Equals ( key , i . Key ) ) ;
57+
58+ return ! Equals ( default ( ObservableKeyValuePair < TKey , TValue > ) , r ) ;
59+ }
60+
61+ /// <summary>
62+ /// Determines whether two keys are equal using the default equality comparer for the key type.
63+ /// </summary>
64+ /// <param name="a">The first key to compare.</param>
65+ /// <param name="b">The second key to compare.</param>
66+ /// <returns><c>true</c> if the keys are equal; otherwise, <c>false</c>.</returns>
67+ private static bool Equals ( TKey a , TKey b )
68+ {
69+ return EqualityComparer < TKey > . Default . Equals ( a , b ) ;
70+ }
71+
72+ /// <summary>
73+ /// Converts the dictionary to an ObservableCollection of key-value pairs.
74+ /// </summary>
75+ /// <returns>An ObservableCollection of key-value pairs.</returns>
76+ private ObservableCollection < ObservableKeyValuePair < TKey , TValue > > ThisAsCollection ( )
77+ {
78+ return this ;
79+ }
80+
81+ /// <summary>
82+ /// Gets a collection containing the keys of the dictionary.
83+ /// </summary>
84+ public ICollection < TKey > Keys
85+ {
86+ get { return ( from i in ThisAsCollection ( ) select i . Key ) . ToList ( ) ; }
87+ }
88+
89+ /// <summary>
90+ /// Removes all elements from the dictionary.
91+ /// </summary>
92+ public virtual new void Clear ( )
93+ {
94+ base . Clear ( ) ;
95+ }
96+
97+ /// <summary>
98+ /// Removes the element with the specified key from the dictionary.
99+ /// </summary>
100+ /// <param name="key">The key of the element to remove.</param>
101+ /// <returns><c>true</c> if the element is successfully removed; otherwise, <c>false</c>.</returns>
102+ public virtual bool Remove ( TKey key )
103+ {
104+ var remove = ThisAsCollection ( ) . Where ( pair => ObservableDictionary < TKey , TValue > . Equals ( key , pair . Key ) ) . ToList ( ) ;
105+ foreach ( var pair in remove )
106+ {
107+ ThisAsCollection ( ) . Remove ( pair ) ;
108+ }
109+ return remove . Count > 0 ;
110+ }
111+
112+ /// <summary>
113+ /// Gets the value associated with the specified key.
114+ /// </summary>
115+ /// <param name="key">The key to locate in the dictionary.</param>
116+ /// <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 <typeparamref name="TValue"/> parameter.</param>
117+ /// <returns><c>true</c> if the dictionary contains an element with the specified key; otherwise, <c>false</c>.</returns>
118+ public virtual bool TryGetValue ( TKey key , out TValue value )
119+ {
120+ #nullable disable
121+ value = default ;
122+ #nullable restore
123+ var r = GetKvpByTheKey ( key ) ;
124+ if ( r == null )
125+ {
126+ return false ;
127+ }
128+ value = r . Value ;
129+ return true ;
130+ }
131+
132+ /// <summary>
133+ /// Gets the key-value pair associated with the specified key.
134+ /// </summary>
135+ /// <param name="key">The key to locate in the dictionary.</param>
136+ /// <returns>The key-value pair associated with the specified key, or <c>null</c> if the key is not found.</returns>
137+ private ObservableKeyValuePair < TKey , TValue > GetKvpByTheKey ( TKey key )
138+ {
139+ #nullable disable
140+ return ThisAsCollection ( ) . FirstOrDefault ( ( i ) => i . Key . Equals ( key ) ) ;
141+ #nullable restore
142+ }
143+
144+ /// <summary>
145+ /// Gets a collection containing the values in the dictionary.
146+ /// </summary>
147+ public ICollection < TValue > Values
148+ {
149+ get { return ( from i in ThisAsCollection ( ) select i . Value ) . ToList ( ) ; }
150+ }
151+
152+ /// <summary>
153+ /// Gets or sets the value associated with the specified key.
154+ /// </summary>
155+ /// <param name="key">The key of the value to get or set.</param>
156+ /// <returns>The value associated with the specified key.</returns>
157+ public TValue this [ TKey key ]
158+ {
159+ get
160+ {
161+ TValue result ;
162+ if ( ! TryGetValue ( key , out result ) )
163+ {
164+ throw new ArgumentException ( "Key not found" ) ;
165+ }
166+ return result ;
167+ }
168+ set
169+ {
170+ if ( ContainsKey ( key ) )
171+ {
172+ GetKvpByTheKey ( key ) . Value = value ;
173+ }
174+ else
175+ {
176+ Add ( key , value ) ;
177+ }
178+ }
179+ }
180+
181+ /// <summary>
182+ /// Adds a key-value pair to the dictionary.
183+ /// </summary>
184+ /// <param name="item">The key-value pair to add to the dictionary.</param>
185+ public virtual void Add ( KeyValuePair < TKey , TValue > item )
186+ {
187+ Add ( item . Key , item . Value ) ;
188+ }
189+
190+ /// <summary>
191+ /// Determines whether the dictionary contains a specific key-value pair.
192+ /// </summary>
193+ /// <param name="item">The key-value pair to locate in the dictionary.</param>
194+ /// <returns><c>true</c> if the dictionary contains the specified key-value pair; otherwise, <c>false</c>.</returns>
195+ public virtual bool Contains ( KeyValuePair < TKey , TValue > item )
196+ {
197+ var r = GetKvpByTheKey ( item . Key ) ;
198+ if ( Equals ( r , default ( ObservableKeyValuePair < TKey , TValue > ) ) )
199+ {
200+ return false ;
201+ }
202+ return Equals ( r . Value , item . Value ) ;
203+ }
204+
205+ /// <summary>
206+ /// Copies the elements of the <see cref="ObservableDictionary{TKey, TValue}"/> to an array of key-value pairs, starting at the specified array index.
207+ /// </summary>
208+ /// <param name="array">The one-dimensional array of key-value pairs that is the destination of the elements copied from the dictionary. The array must have zero-based indexing.</param>
209+ /// <param name="arrayIndex">The zero-based index in the array at which copying begins.</param>
210+ public virtual void CopyTo ( KeyValuePair < TKey , TValue > [ ] array , int arrayIndex )
211+ {
212+ if ( array == null )
213+ {
214+ throw new ArgumentNullException ( nameof ( array ) , "The destination array is null." ) ;
215+ }
216+
217+ if ( arrayIndex < 0 || arrayIndex >= array . Length )
218+ {
219+ throw new ArgumentOutOfRangeException ( nameof ( arrayIndex ) , "The array index is out of range." ) ;
220+ }
221+
222+ if ( array . Length - arrayIndex < Count )
223+ {
224+ throw new ArgumentException ( "The number of elements in the dictionary is greater than the available space from arrayIndex to the end of the destination array." ) ;
225+ }
226+
227+ int i = arrayIndex ;
228+ foreach ( var pair in ThisAsCollection ( ) )
229+ {
230+ array [ i ] = new KeyValuePair < TKey , TValue > ( pair . Key , pair . Value ) ;
231+ i ++ ;
232+ }
233+ }
234+
235+ /// <summary>
236+ /// Gets a value indicating whether the <see cref="ObservableDictionary{TKey, TValue}"/> is read-only.
237+ /// </summary>
238+ /// <value>true if the dictionary is read-only; otherwise, false. This property always returns false.</value>
239+ public bool IsReadOnly
240+ {
241+ get { return false ; }
242+ }
243+
244+ /// <summary>
245+ /// Removes the first occurrence of a specific key and value from the dictionary.
246+ /// </summary>
247+ /// <param name="item">The key-value pair to remove from the dictionary.</param>
248+ /// <returns>true if the key-value pair was successfully removed; otherwise, false.</returns>
249+ public virtual bool Remove ( KeyValuePair < TKey , TValue > item )
250+ {
251+ var r = GetKvpByTheKey ( item . Key ) ;
252+ if ( Equals ( r , default ( ObservableKeyValuePair < TKey , TValue > ) ) )
253+ {
254+ return false ;
255+ }
256+ if ( ! Equals ( r . Value , item . Value ) )
257+ {
258+ return false ;
259+ }
260+ return ThisAsCollection ( ) . Remove ( r ) ;
261+ }
262+
263+ /// <summary>
264+ /// Returns an enumerator that iterates through the <see cref="ObservableDictionary{TKey, TValue}"/>.
265+ /// </summary>
266+ /// <returns>An enumerator for the <see cref="ObservableDictionary{TKey, TValue}"/>.</returns>
267+ public virtual new IEnumerator < KeyValuePair < TKey , TValue > > GetEnumerator ( )
268+ {
269+ return ( from i in ThisAsCollection ( ) select new KeyValuePair < TKey , TValue > ( i . Key , i . Value ) ) . ToList ( ) . GetEnumerator ( ) ;
270+ }
271+ }
272+ }
0 commit comments