1 //------------------------------------------------------------------------------
2 // <copyright file="ModelItemDictionary.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 namespace System.Activities.Presentation.Model {
9 using System.Activities.Presentation.Internal.Properties;
10 using System.Activities.Presentation;
14 using System.Collections;
15 using System.Collections.Generic;
16 using System.Collections.Specialized;
17 using System.Diagnostics.CodeAnalysis;
18 using System.Globalization;
22 /// ModelItemDictionary derives from ModelItem and implements support for a
23 /// dictionary of key/value pairs. Both the keys and values are items.
25 /// ModelItemDictionary defines an attached property "Key", which is adds
26 /// to all items contained in the dictionary. The data type of the Key
27 /// property is "ModelItem" and it is marked as non-browsable and
30 /// In addition to the Key property, ModelItemDictionary also returns an
31 /// Item property from its properties collection just like ModelItemCollection.
32 /// ModelItemDictionary reuses the ModelProperty defined on ModelItemCollection.
33 /// The value returned is an enumeration of the values in the dictionary.
34 /// The Source property of all items in the dictionary refers to this Item
37 public abstract class ModelItemDictionary : ModelItem, IDictionary<ModelItem, ModelItem>, IDictionary, INotifyCollectionChanged {
40 /// Creates a new ModelItemDictionary.
42 protected ModelItemDictionary() { }
45 /// Returns the item at the given key. Sets the item at the given
46 /// key to the given value. If there is no item for the given key
47 /// this returns null because null is not a valid item.
49 /// <param name="key"></param>
50 /// <returns></returns>
51 /// <exception cref="InvalidOperationException">if the dictionary is read only and you set a new value.</exception>
52 /// <exception cref="KeyNotFoundException">if the given key is not in the dictionary.</exception>
53 [SuppressMessage("Microsoft.Design", "CA1043:UseIntegralOrStringArgumentForIndexers")]
54 public abstract ModelItem this[ModelItem key] { get; set; }
57 /// Returns the item at the given key. Sets the item at the given
58 /// key to the given value. If there is no item for the given key
59 /// this returns null because null is not a valid item.
61 /// <param name="key"></param>
62 /// <returns></returns>
63 /// <exception cref="InvalidOperationException">if the dictionary is read only and you set a new value.</exception>
64 /// <exception cref="KeyNotFoundException">if the given key is not in the dictionary.</exception>
65 [SuppressMessage("Microsoft.Design", "CA1043:UseIntegralOrStringArgumentForIndexers")]
66 public abstract ModelItem this[object key] { get; set; }
69 /// Returns the count of items in the dictionary.
71 public abstract int Count { get; }
74 /// Returns true if the dictionary is a fixed size.
75 /// The default implementation returns true if the
76 /// dictionary is read only.
78 protected virtual bool IsFixedSize {
79 get { return IsReadOnly; }
83 /// Returns true if the dictionary cannot be modified.
85 public abstract bool IsReadOnly { get; }
88 /// Protected access to ICollection.IsSynchronized.
90 protected virtual bool IsSynchronized {
95 /// Returns the keys of the collection. The keys are guaranteed to be in
96 /// the same order as the values. The resulting collection is read-only.
98 [Fx.Tag.KnownXamlExternalAttribute]
99 public abstract ICollection<ModelItem> Keys { get; }
102 /// Protected access to the SyncRoot object used to synchronize
103 /// this collection. The default value returns "this".
105 protected virtual object SyncRoot {
110 /// Returns the values of the collection. The values are guaranteed to be
111 /// in the same order as the keys. The resulting collection is read-only.
113 [Fx.Tag.KnownXamlExternalAttribute]
114 public abstract ICollection<ModelItem> Values { get; }
117 /// This event is raised when the contents of this collection change.
119 public abstract event NotifyCollectionChangedEventHandler CollectionChanged;
122 /// Adds the item to the dictionary under the given key.
124 /// <param name="key"></param>
125 /// <param name="value"></param>
126 /// <exception cref="InvalidOperationException">if the dictionary is read only.</exception>
127 public abstract void Add(ModelItem key, ModelItem value);
130 /// Adds the value to the dictionary under the given key. This
131 /// will wrap the key and value in an item. It returns the item
132 /// representing the key.
134 /// <param name="key"></param>
135 /// <param name="value"></param>
136 /// <returns>an item representing the key in the dictionary</returns>
137 /// <exception cref="InvalidOperationException">if the dictionary is read only.</exception>
138 public abstract ModelItem Add(object key, object value);
141 /// Clears the contents of the dictionary.
143 /// <exception cref="InvalidOperationException">if the dictionary is read only.</exception>
144 public abstract void Clear();
147 /// Copies into the given array.
149 /// <param name="array"></param>
150 /// <param name="arrayIndex"></param>
151 protected virtual void CopyTo(KeyValuePair<ModelItem, ModelItem>[] array, int arrayIndex) {
152 foreach (KeyValuePair<ModelItem, ModelItem> kv in this) {
153 array[arrayIndex++] = kv;
158 /// Returns true if the dictionary contains the given key value pair.
160 protected virtual bool Contains(KeyValuePair<ModelItem, ModelItem> item) {
162 return TryGetValue(item.Key, out value) && value == item.Value;
166 /// Returns true if the dictionary contains the given key.
168 /// <param name="key"></param>
169 /// <returns></returns>
170 public abstract bool ContainsKey(ModelItem key);
173 /// Returns true if the dictionary contains the given key.
175 /// <param name="key"></param>
176 /// <returns></returns>
177 public abstract bool ContainsKey(object key);
180 // Helper method that verifies that objects can be upcast to
183 private static ModelItem ConvertType(object value) {
185 return (ModelItem)value;
187 catch (InvalidCastException) {
188 throw FxTrace.Exception.AsError(new ArgumentException(
189 string.Format(CultureInfo.CurrentCulture,
190 Resources.Error_ArgIncorrectType,
191 "value", typeof(ModelItem).FullName)));
196 /// Returns an enumerator for the items in the dictionary.
198 /// <returns></returns>
199 [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
200 public abstract IEnumerator<KeyValuePair<ModelItem, ModelItem>> GetEnumerator();
203 /// Removes the item from the dictionary. This does nothing if the item
204 /// does not exist in the collection.
206 /// <param name="key"></param>
207 /// <exception cref="InvalidOperationException">if the dictionary is read only.</exception>
208 public abstract bool Remove(ModelItem key);
211 /// Removes the item from the dictionary. This does nothing if the item
212 /// does not exist in the collection.
214 /// <param name="key"></param>
215 /// <exception cref="InvalidOperationException">if the dictionary is read only.</exception>
216 public abstract bool Remove(object key);
219 /// Retrieves the value for the given key, or returns false if the
220 /// value can
\92t be found.
222 /// <param name="key"></param>
223 /// <param name="value"></param>
224 /// <returns></returns>
225 public abstract bool TryGetValue(ModelItem key, out ModelItem value);
228 /// Retrieves the value for the given key, or returns false if the
229 /// value can
\92t be found.
231 /// <param name="key"></param>
232 /// <param name="value"></param>
233 /// <returns></returns>
234 public abstract bool TryGetValue(object key, out ModelItem value);
237 /// ModelItemDictionary provides an attached property "Key", which is adds to
238 /// all items contained in the dictionary. The data type of the Key
239 /// property is "ModelItem".
241 public static readonly DependencyProperty KeyProperty = DependencyProperty.RegisterAttachedReadOnly(
244 typeof(ModelItemDictionary), null).DependencyProperty;
246 // IDictionary API is synthesized on top of the generic API.
248 #region IDictionary Members
251 /// IDictionary Implementation maps back to public API.
253 void IDictionary.Add(object key, object value) {
258 /// IDictionary Implementation maps back to public API.
260 void IDictionary.Clear() {
265 /// IDictionary Implementation maps back to public API.
267 [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]
268 bool IDictionary.Contains(object key) {
269 return ContainsKey(key);
273 /// IDictionary Implementation maps back to public API.
275 IDictionaryEnumerator IDictionary.GetEnumerator() {
276 return new DictionaryEnumerator(GetEnumerator());
280 /// IDictionary Implementation maps back to public API.
282 bool IDictionary.IsFixedSize {
283 get { return IsFixedSize; }
287 /// IDictionary Implementation maps back to public API.
289 bool IDictionary.IsReadOnly {
290 get { return IsReadOnly; }
294 /// IDictionary Implementation maps back to public API.
296 ICollection IDictionary.Keys
299 object[] keys = new object[Count];
301 foreach (KeyValuePair<ModelItem, ModelItem> kv in this) {
302 keys[idx++] = kv.Key;
309 /// IDictionary Implementation maps back to public API.
311 void IDictionary.Remove(object key) {
316 /// IDictionary Implementation maps back to public API.
318 ICollection IDictionary.Values
321 object[] values = new object[Count];
323 foreach (KeyValuePair<ModelItem, ModelItem> kv in this) {
324 values[idx++] = kv.Value;
331 /// IDictionary Implementation maps back to public API.
333 object IDictionary.this[object key] {
334 get { return this[ConvertType(key)]; }
335 set { this[ConvertType(key)] = ConvertType(value); }
340 #region ICollection Members
343 /// ICollection Implementation maps back to public API.
345 void ICollection.CopyTo(Array array, int index) {
348 int len = array.GetLength(0);
350 throw FxTrace.Exception.AsError(new ArgumentException(
351 string.Format(CultureInfo.CurrentCulture,
352 Resources.Error_InvalidArrayIndex, index)));
355 KeyValuePair<ModelItem, ModelItem>[] typedArray = new KeyValuePair<ModelItem, ModelItem>[len];
357 CopyTo(typedArray, index);
359 for (; index < typedArray.Length; index++) {
360 array.SetValue(typedArray[index], index);
366 /// ICollection Implementation maps back to public API.
368 int ICollection.Count {
369 get { return Count; }
373 /// ICollection Implementation maps back to public API.
375 bool ICollection.IsSynchronized {
376 get { return IsSynchronized; }
380 /// ICollection Implementation maps back to public API.
382 object ICollection.SyncRoot {
383 get { return SyncRoot; }
388 #region IEnumerable Members
391 /// IEnumerator Implementation maps back to public API.
393 IEnumerator IEnumerable.GetEnumerator() {
394 foreach (KeyValuePair<ModelItem, ModelItem> kv in this) {
401 #region ICollection<KeyValuePair<ModelItem,ModelItem>> Members
403 void ICollection<KeyValuePair<ModelItem, ModelItem>>.Add(KeyValuePair<ModelItem, ModelItem> item) {
404 Add(item.Key, item.Value);
407 bool ICollection<KeyValuePair<ModelItem, ModelItem>>.Contains(KeyValuePair<ModelItem, ModelItem> item) {
408 return Contains(item);
411 void ICollection<KeyValuePair<ModelItem, ModelItem>>.CopyTo(KeyValuePair<ModelItem, ModelItem>[] array, int arrayIndex) {
412 if (arrayIndex >= array.Length) {
413 throw FxTrace.Exception.AsError(new ArgumentException(
414 string.Format(CultureInfo.CurrentCulture,
415 Resources.Error_InvalidArrayIndex, arrayIndex)));
418 CopyTo(array, arrayIndex);
421 bool ICollection<KeyValuePair<ModelItem, ModelItem>>.Remove(KeyValuePair<ModelItem, ModelItem> item) {
423 if (TryGetValue(item.Key, out value) && value == item.Value) {
424 return Remove(item.Key);
433 // This is a simple struct that implements a dictionary enumerator,
434 // since this isn't supported in the iterator pattern.
436 private struct DictionaryEnumerator : IDictionaryEnumerator {
438 private IEnumerator<KeyValuePair<ModelItem, ModelItem>> _real;
440 internal DictionaryEnumerator(IEnumerator<KeyValuePair<ModelItem, ModelItem>> real) {
444 #region IDictionaryEnumerator Members
446 public DictionaryEntry Entry {
447 get { return new DictionaryEntry(_real.Current.Key, _real.Current.Value); }
451 get { return _real.Current.Key; }
454 public object Value {
455 get { return _real.Current.Value; }
460 #region IEnumerator Members
462 public object Current {
463 get { return Entry; }
466 public bool MoveNext() {
467 return _real.MoveNext();
470 public void Reset() {