Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / FreezableCollection.cs / 1305600 / FreezableCollection.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: This file contains the implementation of FreezableCollection. // FreezableCollection is an IList implementation which implements // the requisite infrastructure for collections of DependencyObjects, // Freezables, and Animatables and which is itself an Animatable and a Freezable. // //--------------------------------------------------------------------------- using MS.Internal; using MS.Internal.KnownBoxes; using MS.Internal.Collections; using MS.Internal.PresentationCore; using MS.Utility; using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.InteropServices; using System.ComponentModel.Design.Serialization; using System.Text; using System.Windows; using System.Windows.Media; using System.Windows.Media.Effects; using System.Windows.Media.Media3D; using System.Windows.Media.Animation; using System.Windows.Media.Composition; using System.Windows.Media.Imaging; using System.Windows.Markup; using System.Windows.Media.Converters; using System.Security; using System.Security.Permissions; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; // These types are aliased to match the unamanaged names used in interop using BOOL = System.UInt32; using WORD = System.UInt16; using Float = System.Single; namespace System.Windows { /// /// FreezableCollection<T> is an IList<T> implementation which implements /// the requisite infrastructure for collections of DependencyObjects, /// Freezables, and Animatables and which is itself an Animatable and a Freezable. /// public class FreezableCollection: Animatable, IList, IList , INotifyCollectionChanged, INotifyPropertyChanged where T: DependencyObject { #region Constructors //----------------------------------------------------- // // Constructors // //----------------------------------------------------- /// /// Initializes a new instance that is empty. /// public FreezableCollection() { _collection = new List(); } /// /// Initializes a new instance that is empty and has the specified initial capacity. /// /// int - The number of elements that the new list is initially capable of storing. public FreezableCollection(int capacity) { _collection = new List(capacity); } /// /// Creates a FreezableCollection<T> with all of the same elements as "collection" /// public FreezableCollection(IEnumerablecollection) { // The WritePreamble and WritePostscript aren't technically necessary // in the constructor as of 1/20/05 but they are put here in case // their behavior changes at a later date WritePreamble(); if (collection != null) { int count = GetCount(collection); if (count > 0) { _collection = new List (count); } else { _collection = new List (); } foreach (T item in collection) { if (item == null) { throw new System.ArgumentException(SR.Get(SRID.Collection_NoNull)); } OnFreezablePropertyChanged(/* oldValue = */ null, item); _collection.Add(item); } WritePostscript(); } else { throw new ArgumentNullException("collection"); } } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods /// /// Shadows inherited Clone() with a strongly typed /// version for convenience. /// public new FreezableCollectionClone() { return (FreezableCollection )base.Clone(); } /// /// Shadows inherited CloneCurrentValue() with a strongly typed /// version for convenience. /// public new FreezableCollectionCloneCurrentValue() { return (FreezableCollection )base.CloneCurrentValue(); } #endregion Public Methods //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ #region IList /// /// Adds "value" to the list /// public void Add(T value) { AddHelper(value); } ////// Removes all elements from the list /// public void Clear() { CheckReentrancy(); WritePreamble(); for (int i = _collection.Count - 1; i >= 0; i--) { OnFreezablePropertyChanged(/* oldValue = */ _collection[i], /* newValue = */ null); } _collection.Clear(); Debug.Assert(_collection.Count == 0); ++_version; WritePostscript(); OnCollectionChanged(NotifyCollectionChangedAction.Reset, 0, null, 0, null); } ////// Determines if the list contains "value" /// public bool Contains(T value) { ReadPreamble(); return _collection.Contains(value); } ////// Returns the index of "value" in the list /// public int IndexOf(T value) { ReadPreamble(); return _collection.IndexOf(value); } ////// Inserts "value" into the list at the specified position /// public void Insert(int index, T value) { if (value == null) { throw new System.ArgumentException(SR.Get(SRID.Collection_NoNull)); } CheckReentrancy(); WritePreamble(); OnFreezablePropertyChanged(/* oldValue = */ null, /* newValue = */ value); _collection.Insert(index, value); ++_version; WritePostscript(); OnCollectionChanged(NotifyCollectionChangedAction.Add, 0, null, index, value); } ////// Removes "value" from the list /// public bool Remove(T value) { WritePreamble(); // By design collections "succeed silently" if you attempt to remove an item // not in the collection. Therefore we need to first verify the old value exists // before calling OnFreezablePropertyChanged. Since we already need to locate // the item in the collection we keep the index and use RemoveAt(...) to do // the work. (Windows OS #1016178) // We use the public IndexOf to guard our UIContext since OnFreezablePropertyChanged // is only called conditionally. IList.IndexOf returns -1 if the value is not found. int index = IndexOf(value); if (index >= 0) { CheckReentrancy(); T oldValue = _collection[index]; OnFreezablePropertyChanged(oldValue, null); // we already have index from IndexOf so instead of using Remove - // which will search the collection a second time - we'll use RemoveAt _collection.RemoveAt(index); ++_version; WritePostscript(); OnCollectionChanged(NotifyCollectionChangedAction.Remove, index, oldValue, 0, null); return true; } // Collection_Remove returns true, calls WritePostscript, // increments version, and does UpdateResource if it succeeds return false; } ////// Removes the element at the specified index /// public void RemoveAt(int index) { T oldValue = _collection[ index ]; RemoveAtWithoutFiringPublicEvents(index); // RemoveAtWithoutFiringPublicEvents incremented the version WritePostscript(); OnCollectionChanged(NotifyCollectionChangedAction.Remove, index, oldValue, 0, null); } ////// Removes the element at the specified index without firing /// the public Changed event. /// The caller - typically a public method - is responsible for calling /// WritePostscript if appropriate. /// internal void RemoveAtWithoutFiringPublicEvents(int index) { CheckReentrancy(); WritePreamble(); T oldValue = _collection[ index ]; OnFreezablePropertyChanged(oldValue, null); _collection.RemoveAt(index); ++_version; // No WritePostScript to avoid firing the Changed event. } ////// Indexer for the collection /// public T this[int index] { get { ReadPreamble(); return _collection[index]; } set { if (value == null) { throw new System.ArgumentException(SR.Get(SRID.Collection_NoNull)); } CheckReentrancy(); WritePreamble(); T oldValue = _collection[ index ]; bool isChanging = !Object.ReferenceEquals(oldValue, value); if (isChanging) { OnFreezablePropertyChanged(oldValue, value); _collection[ index ] = value; } ++_version; WritePostscript(); if (isChanging) { OnCollectionChanged(NotifyCollectionChangedAction.Replace, index, oldValue, index, value); } } } #endregion #region ICollection/// /// The number of elements contained in the collection. /// public int Count { get { ReadPreamble(); return _collection.Count; } } ////// Copies the elements of the collection into "array" starting at "index" /// public void CopyTo(T[] array, int index) { ReadPreamble(); if (array == null) { throw new ArgumentNullException("array"); } // This will not throw in the case that we are copying // from an empty collection. This is consistent with the // BCL Collection implementations. (Windows 1587365) if (index < 0 || (index + _collection.Count) > array.Length) { throw new ArgumentOutOfRangeException("index"); } _collection.CopyTo(array, index); } bool ICollection.IsReadOnly { get { ReadPreamble(); return IsFrozen; } } #endregion #region IEnumerable /// /// Returns an enumerator for the collection /// public Enumerator GetEnumerator() { ReadPreamble(); return new Enumerator(this); } IEnumeratorIEnumerable .GetEnumerator() { return this.GetEnumerator(); } #endregion #region IList bool IList.IsReadOnly { get { return ((ICollection )this).IsReadOnly; } } bool IList.IsFixedSize { get { ReadPreamble(); return IsFrozen; } } object IList.this[int index] { get { return this[index]; } set { // Forwards to typed implementation this[index] = Cast(value); } } int IList.Add(object value) { // Forward to typed helper return AddHelper(Cast(value)); } bool IList.Contains(object value) { return Contains(value as T); } int IList.IndexOf(object value) { return IndexOf(value as T); } void IList.Insert(int index, object value) { // Forward to IList Insert Insert(index, Cast(value)); } void IList.Remove(object value) { Remove(value as T); } #endregion #region ICollection void ICollection.CopyTo(Array array, int index) { ReadPreamble(); if (array == null) { throw new ArgumentNullException("array"); } // This will not throw in the case that we are copying // from an empty collection. This is consistent with the // BCL Collection implementations. (Windows 1587365) if (index < 0 || (index + _collection.Count) > array.Length) { throw new ArgumentOutOfRangeException("index"); } if (array.Rank != 1) { throw new ArgumentException(SR.Get(SRID.Collection_BadRank)); } // Elsewhere in the collection we throw an AE when the type is // bad so we do it here as well to be consistent try { int count = _collection.Count; for (int i = 0; i < count; i++) { array.SetValue(_collection[i], index + i); } } catch (InvalidCastException e) { throw new ArgumentException(SR.Get(SRID.Collection_BadDestArray, this.GetType().Name), e); } } bool ICollection.IsSynchronized { get { ReadPreamble(); return IsFrozen || Dispatcher != null; } } object ICollection.SyncRoot { get { ReadPreamble(); return this; } } #endregion #region IEnumerable IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } #endregion #region INotifyCollectionChanged /// /// CollectionChanged event (per event NotifyCollectionChangedEventHandler INotifyCollectionChanged.CollectionChanged { add { CollectionChanged += value; } remove { CollectionChanged -= value; } } ///). /// /// Occurs when the collection changes, either by adding or removing an item. /// ////// see private event NotifyCollectionChangedEventHandler CollectionChanged; ////// /// Raise CollectionChanged event to any listeners. /// Properties/methods modifying this FreezableCollection will raise /// a collection changed event through this method. /// private void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (CollectionChanged != null) { using (BlockReentrancy()) { CollectionChanged(this, e); } } } #endregion INotifyCollectionChanged #region INotifyPropertyChanged ////// PropertyChanged event (per event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged { add { PrivatePropertyChanged += value; } remove { PrivatePropertyChanged -= value; } } ///). /// /// PropertyChanged event (per // We can't call this "PropertyChanged" because the base class Animatable // declares an internal method with that name. private event PropertyChangedEventHandler PrivatePropertyChanged; ///). /// /// Raises a PropertyChanged event (per private void OnPropertyChanged(PropertyChangedEventArgs e) { if (PrivatePropertyChanged != null) { PrivatePropertyChanged(this, e); } } #endregion INotifyPropertyChanged #region Internal Helpers ///). /// /// Freezable collections need to notify their contained Freezables /// about the change in the InheritanceContext /// internal override void OnInheritanceContextChangedCore(EventArgs args) { base.OnInheritanceContextChangedCore(args); for (int i=0; iby sniffing for the // ICollection and ICollection interfaces. If the count can not be // extract it return -1. private int GetCount(IEnumerable enumerable) { ICollection collectionAsICollection = enumerable as ICollection; if (collectionAsICollection != null) { return collectionAsICollection.Count; } ICollection enumerableAsICollectionT = enumerable as ICollection ; if (enumerableAsICollectionT != null) { return enumerableAsICollectionT.Count; } // We return -1 here and force the caller to decide how to handle // the unknown case. In the future different collections might // use different estimates for unknown. (e.g., Point3DCollections // tend to be 8+ while DoubleCollections are freqently <= 2, etc.) return -1; } // IList.Add returns int and IList .Add does not. This // is called by both Adds and IList 's just ignores the // integer private int AddHelper(T value) { CheckReentrancy(); int index = AddWithoutFiringPublicEvents(value); // AddAtWithoutFiringPublicEvents incremented the version WritePostscript(); // OnCollectionChanged(NotifyCollectionChangedAction.Add, 0, null, index-1, value); return index; } internal int AddWithoutFiringPublicEvents(T value) { if (value == null) { throw new System.ArgumentException(SR.Get(SRID.Collection_NoNull)); } WritePreamble(); T newValue = value; OnFreezablePropertyChanged(/* oldValue = */ null, newValue); _collection.Add(value); ++_version; // No WritePostScript to avoid firing the Changed event. // return _collection.Count; } // helper to raise events after the collection has changed private void OnCollectionChanged(NotifyCollectionChangedAction action, int oldIndex, T oldValue, int newIndex, T newValue) { if (PrivatePropertyChanged == null && CollectionChanged == null) return; using (BlockReentrancy()) { // most collection changes imply a change in the Count and indexer // properties if (PrivatePropertyChanged != null) { if (action != NotifyCollectionChangedAction.Replace && action != NotifyCollectionChangedAction.Move) { OnPropertyChanged(new PropertyChangedEventArgs(CountPropertyName)); } OnPropertyChanged(new PropertyChangedEventArgs(IndexerPropertyName)); } if (CollectionChanged != null) { NotifyCollectionChangedEventArgs args; switch (action) { case NotifyCollectionChangedAction.Reset: args = new NotifyCollectionChangedEventArgs(action); break; case NotifyCollectionChangedAction.Add: args = new NotifyCollectionChangedEventArgs(action, newValue, newIndex); break; case NotifyCollectionChangedAction.Remove: args = new NotifyCollectionChangedEventArgs(action, oldValue, oldIndex); break; case NotifyCollectionChangedAction.Replace: args = new NotifyCollectionChangedEventArgs(action, newValue, oldValue, newIndex); break; default: throw new InvalidOperationException(SR.Get(SRID.Freezable_UnexpectedChange)); } OnCollectionChanged(args); } } } #endregion Private Helpers //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ #region Protected Methods /// /// Implementation of ///Freezable.CreateInstanceCore . ///The new Freezable. protected override Freezable CreateInstanceCore() { return new FreezableCollection(); } enum CloneCommonType { Clone, CloneCurrentValue, GetAsFrozen, GetCurrentValueAsFrozen } private void CloneCommon(FreezableCollection source, CloneCommonType cloneType) { int count = source._collection.Count; _collection = new List (count); for (int i = 0; i < count; i++) { T newValue = source._collection[i]; Freezable itemAsFreezable = newValue as Freezable; if (itemAsFreezable != null) { switch (cloneType) { case CloneCommonType.Clone: newValue = itemAsFreezable.Clone() as T; break; case CloneCommonType.CloneCurrentValue: newValue = itemAsFreezable.CloneCurrentValue() as T; break; case CloneCommonType.GetAsFrozen: newValue = itemAsFreezable.GetAsFrozen() as T; break; case CloneCommonType.GetCurrentValueAsFrozen: newValue = itemAsFreezable.GetCurrentValueAsFrozen() as T; break; default: Invariant.Assert(false, "Invalid CloneCommonType encountered."); break; } if (newValue == null) { throw new InvalidOperationException(SR.Get(SRID.Freezable_CloneInvalidType, typeof(T).Name)); } } OnFreezablePropertyChanged(/* oldValue = */ null, newValue); _collection.Add(newValue); } } /// /// Implementation of Freezable.CloneCore() /// protected override void CloneCore(Freezable source) { base.CloneCore(source); FreezableCollectionsourceFreezableCollection = (FreezableCollection ) source; CloneCommon(sourceFreezableCollection, CloneCommonType.Clone); } /// /// Implementation of Freezable.CloneCurrentValueCore() /// protected override void CloneCurrentValueCore(Freezable source) { base.CloneCurrentValueCore(source); FreezableCollectionsourceFreezableCollection = (FreezableCollection ) source; CloneCommon(sourceFreezableCollection, CloneCommonType.CloneCurrentValue); } /// /// Implementation of Freezable.GetAsFrozenCore() /// protected override void GetAsFrozenCore(Freezable source) { base.GetAsFrozenCore(source); FreezableCollectionsourceFreezableCollection = (FreezableCollection ) source; CloneCommon(sourceFreezableCollection, CloneCommonType.GetAsFrozen); } /// /// Implementation of Freezable.GetCurrentValueAsFrozenCore() /// protected override void GetCurrentValueAsFrozenCore(Freezable source) { base.GetCurrentValueAsFrozenCore(source); FreezableCollectionsourceFreezableCollection = (FreezableCollection ) source; CloneCommon(sourceFreezableCollection, CloneCommonType.GetCurrentValueAsFrozen); } /// /// Implementation of protected override bool FreezeCore(bool isChecking) { bool canFreeze = base.FreezeCore(isChecking); int count = _collection.Count; for (int i = 0; i < count && canFreeze; i++) { T item = _collection[i]; Freezable itemAsFreezable = item as Freezable; if (itemAsFreezable != null) { canFreeze &= Freezable.Freeze(itemAsFreezable, isChecking); } else { canFreeze &= (item.Dispatcher == null); } } return canFreeze; } ///Freezable.FreezeCore . ////// Disallow reentrant attempts to change this collection. E.g. a event handler /// of the CollectionChanged event is not allowed to make changes to this collection. /// ////// typical usage is to wrap e.g. a OnCollectionChanged call with a using() scope: /// private IDisposable BlockReentrancy() { _monitor.Enter(); return _monitor; } ////// using (BlockReentrancy()) /// { /// CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, item, index)); /// } ///
///Check and assert for reentrant attempts to change this collection. ///raised when changing the collection /// while another collection change is still being notified to other listeners private void CheckReentrancy() { if (_monitor.Busy) { throw new InvalidOperationException(SR.Get(SRID.Freezable_Reentrant)); } } #endregion ProtectedMethods //----------------------------------------------------- // // Internal Fields // //----------------------------------------------------- #region Internal Fields internal List_collection; internal uint _version = 0; #endregion Internal Fields //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields private const string CountPropertyName = "Count"; // This must agree with Binding.IndexerName. It is declared separately // here so as to avoid a dependency on PresentationFramework.dll. private const string IndexerPropertyName = "Item[]"; private SimpleMonitor _monitor = new SimpleMonitor(); #endregion Private Fields #region Enumerator /// /// Enumerates the items in a TCollection /// public struct Enumerator : IEnumerator, IEnumerator{ #region Constructor internal Enumerator(FreezableCollection list) { Debug.Assert(list != null, "list may not be null."); _list = list; _version = list._version; _index = -1; _current = default(T); } #endregion #region Methods void IDisposable.Dispose() { } /// /// Advances the enumerator to the next element of the collection. /// ////// true if the enumerator was successfully advanced to the next element, /// false if the enumerator has passed the end of the collection. /// public bool MoveNext() { _list.ReadPreamble(); if (_version == _list._version) { if (_index > -2 && _index < _list._collection.Count - 1) { _current = _list._collection[++_index]; return true; } else { _index = -2; // -2 indicates "past the end" return false; } } else { throw new InvalidOperationException(SR.Get(SRID.Enumerator_CollectionChanged)); } } ////// Sets the enumerator to its initial position, which is before the /// first element in the collection. /// public void Reset() { _list.ReadPreamble(); if (_version == _list._version) { _index = -1; } else { throw new InvalidOperationException(SR.Get(SRID.Enumerator_CollectionChanged)); } } #endregion #region Properties object IEnumerator.Current { get { return this.Current; } } ////// Current element /// /// The behavior of IEnumerable<T>.Current is undefined /// before the first MoveNext and after we have walked /// off the end of the list. However, the IEnumerable.Current /// contract requires that we throw exceptions /// public T Current { get { if (_index > -1) { return _current; } else if (_index == -1) { throw new InvalidOperationException(SR.Get(SRID.Enumerator_NotStarted)); } else { Debug.Assert(_index == -2, "expected -2, got " + _index + "\n"); throw new InvalidOperationException(SR.Get(SRID.Enumerator_ReachedEnd)); } } } #endregion #region Data private T _current; private FreezableCollection_list; private uint _version; private int _index; #endregion } private class SimpleMonitor : IDisposable { public void Enter() { ++ _busyCount; } public void Dispose() { -- _busyCount; GC.SuppressFinalize(this); } public bool Busy { get { return _busyCount > 0; } } int _busyCount; } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DocumentGrid.cs
- DecimalAnimationBase.cs
- ComplexBindingPropertiesAttribute.cs
- PropertyTabAttribute.cs
- XsdValidatingReader.cs
- HtmlTableRow.cs
- ScriptRegistrationManager.cs
- MetabaseServerConfig.cs
- PerformanceCounterManager.cs
- OdbcErrorCollection.cs
- SqlError.cs
- TheQuery.cs
- ConfigPathUtility.cs
- InternalEnumValidatorAttribute.cs
- _ConnectStream.cs
- TimeIntervalCollection.cs
- ObjectDataSource.cs
- Exception.cs
- WsdlInspector.cs
- OlePropertyStructs.cs
- Msec.cs
- BitmapEffectCollection.cs
- FilteredAttributeCollection.cs
- AppDomainProtocolHandler.cs
- DataGridPagerStyle.cs
- EntityDataSourceQueryBuilder.cs
- HtmlString.cs
- TypedElement.cs
- PropertyChange.cs
- RoleManagerEventArgs.cs
- InstanceCreationEditor.cs
- AssemblyAttributes.cs
- SafeHandles.cs
- ReadContentAsBinaryHelper.cs
- METAHEADER.cs
- SpecialFolderEnumConverter.cs
- __Filters.cs
- XmlWellformedWriter.cs
- GeneralTransform3DTo2D.cs
- DataGridViewCheckBoxColumn.cs
- ScrollableControl.cs
- ObjectListCommandsPage.cs
- MethodBuilder.cs
- RtType.cs
- MenuCommands.cs
- AutoScrollExpandMessageFilter.cs
- BooleanExpr.cs
- SelectedCellsChangedEventArgs.cs
- DynamicResourceExtension.cs
- CodeSubDirectory.cs
- EtwTrace.cs
- CacheRequest.cs
- Camera.cs
- QuerySetOp.cs
- TrustManager.cs
- BamlRecords.cs
- EntityCommandExecutionException.cs
- SpotLight.cs
- ServiceContractViewControl.Designer.cs
- AuthenticationException.cs
- SamlAuthorizationDecisionClaimResource.cs
- StateManagedCollection.cs
- ServicePointManager.cs
- PasswordDeriveBytes.cs
- PasswordValidationException.cs
- ParallelTimeline.cs
- AttributeSetAction.cs
- BufferAllocator.cs
- WinFormsSpinner.cs
- CheckBox.cs
- ControlDesignerState.cs
- EventManager.cs
- ExternalFile.cs
- ItemsChangedEventArgs.cs
- ConnectionPoint.cs
- FontStyleConverter.cs
- IOException.cs
- OraclePermission.cs
- PropertyDescriptorCollection.cs
- PartialCachingAttribute.cs
- X509KeyIdentifierClauseType.cs
- SqlBulkCopyColumnMappingCollection.cs
- EncryptedType.cs
- PhysicalAddress.cs
- WindowsFormsLinkLabel.cs
- ClientSession.cs
- MTConfigUtil.cs
- Collection.cs
- AlternateView.cs
- FixedStringLookup.cs
- KeyGestureValueSerializer.cs
- XMLUtil.cs
- DigestComparer.cs
- MenuItemCollection.cs
- PerformanceCounterLib.cs
- QueueProcessor.cs
- XmlIgnoreAttribute.cs
- RbTree.cs
- GridItemPatternIdentifiers.cs
- ValidateNames.cs