FreezableCollection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Core / CSharp / System / Windows / FreezableCollection.cs / 1 / 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(IEnumerable collection)
        { 
            // 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 FreezableCollection Clone() 
        { 
            return (FreezableCollection)base.Clone();
        } 

        /// 
        ///     Shadows inherited CloneCurrentValue() with a strongly typed
        ///     version for convenience. 
        /// 
        public new FreezableCollection CloneCurrentValue() 
        { 
            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);
        }
 
        IEnumerator IEnumerable.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; i by 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("Unknown/unexpected change event");
                    } 

                    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);
 
            FreezableCollection sourceFreezableCollection = (FreezableCollection) source;

            CloneCommon(sourceFreezableCollection, CloneCommonType.Clone);
        } 

        ///  
        /// Implementation of Freezable.CloneCurrentValueCore() 
        /// 
        protected override void CloneCurrentValueCore(Freezable source) 
        {
            base.CloneCurrentValueCore(source);

            FreezableCollection sourceFreezableCollection = (FreezableCollection) source; 

            CloneCommon(sourceFreezableCollection, CloneCommonType.CloneCurrentValue); 
        } 
        /// 
        /// Implementation of Freezable.GetAsFrozenCore() 
        /// 
        protected override void GetAsFrozenCore(Freezable source)
        {
            base.GetAsFrozenCore(source); 

            FreezableCollection sourceFreezableCollection = (FreezableCollection) source; 
 
            CloneCommon(sourceFreezableCollection, CloneCommonType.GetAsFrozen);
        } 
        /// 
        /// Implementation of Freezable.GetCurrentValueAsFrozenCore()
        /// 
        protected override void GetCurrentValueAsFrozenCore(Freezable source) 
        {
            base.GetCurrentValueAsFrozenCore(source); 
 
            FreezableCollection sourceFreezableCollection = (FreezableCollection) source;
 
            CloneCommon(sourceFreezableCollection, CloneCommonType.GetCurrentValueAsFrozen);
        }

        ///  
        /// Implementation of Freezable.FreezeCore.
        ///  
        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; 
        }

        /// 
        /// 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:
        ///  
        ///         using (BlockReentrancy())
        ///         {
        ///             CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, item, index));
        ///         } 
        /// 
        ///  
        private IDisposable BlockReentrancy() 
        {
            _monitor.Enter(); 
            return _monitor;
        }

        ///  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("Cannot change FreezableCollection during a CollectionChanged event.");
            } 
        }
 
        #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;
            } 

            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.
//---------------------------------------------------------------------------- 
//
// 
//    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(IEnumerable collection)
        { 
            // 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 FreezableCollection Clone() 
        { 
            return (FreezableCollection)base.Clone();
        } 

        /// 
        ///     Shadows inherited CloneCurrentValue() with a strongly typed
        ///     version for convenience. 
        /// 
        public new FreezableCollection CloneCurrentValue() 
        { 
            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);
        }
 
        IEnumerator IEnumerable.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; i by 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("Unknown/unexpected change event");
                    } 

                    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);
 
            FreezableCollection sourceFreezableCollection = (FreezableCollection) source;

            CloneCommon(sourceFreezableCollection, CloneCommonType.Clone);
        } 

        ///  
        /// Implementation of Freezable.CloneCurrentValueCore() 
        /// 
        protected override void CloneCurrentValueCore(Freezable source) 
        {
            base.CloneCurrentValueCore(source);

            FreezableCollection sourceFreezableCollection = (FreezableCollection) source; 

            CloneCommon(sourceFreezableCollection, CloneCommonType.CloneCurrentValue); 
        } 
        /// 
        /// Implementation of Freezable.GetAsFrozenCore() 
        /// 
        protected override void GetAsFrozenCore(Freezable source)
        {
            base.GetAsFrozenCore(source); 

            FreezableCollection sourceFreezableCollection = (FreezableCollection) source; 
 
            CloneCommon(sourceFreezableCollection, CloneCommonType.GetAsFrozen);
        } 
        /// 
        /// Implementation of Freezable.GetCurrentValueAsFrozenCore()
        /// 
        protected override void GetCurrentValueAsFrozenCore(Freezable source) 
        {
            base.GetCurrentValueAsFrozenCore(source); 
 
            FreezableCollection sourceFreezableCollection = (FreezableCollection) source;
 
            CloneCommon(sourceFreezableCollection, CloneCommonType.GetCurrentValueAsFrozen);
        }

        ///  
        /// Implementation of Freezable.FreezeCore.
        ///  
        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; 
        }

        /// 
        /// 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:
        ///  
        ///         using (BlockReentrancy())
        ///         {
        ///             CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, item, index));
        ///         } 
        /// 
        ///  
        private IDisposable BlockReentrancy() 
        {
            _monitor.Enter(); 
            return _monitor;
        }

        ///  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("Cannot change FreezableCollection during a CollectionChanged event.");
            } 
        }
 
        #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;
            } 

            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

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK