ObservableCollection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / CompMod / System / Collections / ObjectModel / ObservableCollection.cs / 1305376 / ObservableCollection.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) 2003 by Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: Implementation of an Collection implementing INotifyCollectionChanged 
//              to notify listeners of dynamic changes of the list.
// 
// See spec at http://avalon/connecteddata/Specs/Collection%20Interfaces.mht
//
// History:
//  11/22/2004 : [....] - created 
//
//--------------------------------------------------------------------------- 
 
using System;
using System.Collections; 
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Runtime.CompilerServices; 

namespace System.Collections.ObjectModel 
{ 
    /// 
    /// Implementation of a dynamic data collection based on generic Collection<T>, 
    /// implementing INotifyCollectionChanged to notify listeners
    /// when items get added, removed or the whole list is refreshed.
    /// 
    [Serializable()] 
    [TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
    public class ObservableCollection : Collection, INotifyCollectionChanged, INotifyPropertyChanged 
    { 
        //-----------------------------------------------------
        // 
        //  Constructors
        //
        //-----------------------------------------------------
 
        #region Constructors
        ///  
        /// Initializes a new instance of ObservableCollection that is empty and has default initial capacity. 
        /// 
        public ObservableCollection() : base() { } 

        /// 
        /// Initializes a new instance of the ObservableCollection class
        /// that contains elements copied from the specified list 
        /// 
        /// The list whose elements are copied to the new list. 
        ///  
        /// The elements are copied onto the ObservableCollection in the
        /// same order they are read by the enumerator of the list. 
        /// 
        ///  list is a null reference 
        public ObservableCollection(List list)
            : base((list != null) ? new List(list.Count) : list) 
        {
            // Workaround for VSWhidbey bug 562681 (tracked by Windows bug 1369339). 
            // We should be able to simply call the base(list) ctor.  But Collection 
            // doesn't copy the list (contrary to the documentation) - it uses the
            // list directly as its storage.  So we do the copying here. 
            //
            CopyFrom(list);
        }
 
        /// 
        /// Initializes a new instance of the ObservableCollection class that contains 
        /// elements copied from the specified collection and has sufficient capacity 
        /// to accommodate the number of elements copied.
        ///  
        /// The collection whose elements are copied to the new list.
        /// 
        /// The elements are copied onto the ObservableCollection in the
        /// same order they are read by the enumerator of the collection. 
        /// 
        ///  collection is a null reference  
        public ObservableCollection(IEnumerable collection) 
        {
            if (collection == null) 
                throw new ArgumentNullException("collection");

            CopyFrom(collection);
        } 

        private void CopyFrom(IEnumerable collection) 
        { 
            IList items = Items;
            if (collection != null && items != null) 
            {
                using (IEnumerator enumerator = collection.GetEnumerator())
                {
                    while (enumerator.MoveNext()) 
                    {
                        items.Add(enumerator.Current); 
                    } 
                }
            } 
        }

        #endregion Constructors
 

        //------------------------------------------------------ 
        // 
        //  Public Methods
        // 
        //-----------------------------------------------------

        #region Public Methods
 
        /// 
        /// Move item at oldIndex to newIndex. 
        ///  
        public void Move(int oldIndex, int newIndex)
        { 
            MoveItem(oldIndex, newIndex);
        }

        #endregion Public Methods 

 
        //------------------------------------------------------ 
        //
        //  Public Events 
        //
        //------------------------------------------------------

        #region Public Events 

        //----------------------------------------------------- 
        #region INotifyPropertyChanged implementation 

        ///  
        /// PropertyChanged event (per ).
        /// 
        event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
        { 
            add
            { 
                PropertyChanged += value; 
            }
            remove 
            {
                PropertyChanged -= value;
            }
        } 
        #endregion INotifyPropertyChanged implementation
 
 
        //------------------------------------------------------
        ///  
        /// Occurs when the collection changes, either by adding or removing an item.
        /// 
        /// 
        /// see  
        /// 
        [field:NonSerializedAttribute()] 
        public virtual event NotifyCollectionChangedEventHandler CollectionChanged; 

        #endregion Public Events 


        //-----------------------------------------------------
        // 
        //  Protected Methods
        // 
        //----------------------------------------------------- 

        #region Protected Methods 

        /// 
        /// Called by base class Collection<T> when the list is being cleared;
        /// raises a CollectionChanged event to any listeners. 
        /// 
        protected override void ClearItems() 
        { 
            CheckReentrancy();
            base.ClearItems(); 
            OnPropertyChanged(CountString);
            OnPropertyChanged(IndexerName);
            OnCollectionReset();
        } 

        ///  
        /// Called by base class Collection<T> when an item is removed from list; 
        /// raises a CollectionChanged event to any listeners.
        ///  
        protected override void RemoveItem(int index)
        {
            CheckReentrancy();
            T removedItem  = this[index]; 

            base.RemoveItem(index); 
 
            OnPropertyChanged(CountString);
            OnPropertyChanged(IndexerName); 
            OnCollectionChanged(NotifyCollectionChangedAction.Remove, removedItem, index);
        }

        ///  
        /// Called by base class Collection<T> when an item is added to list;
        /// raises a CollectionChanged event to any listeners. 
        ///  
        protected override void InsertItem(int index, T item)
        { 
            CheckReentrancy();
            base.InsertItem(index, item);

            OnPropertyChanged(CountString); 
            OnPropertyChanged(IndexerName);
            OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index); 
        } 

        ///  
        /// Called by base class Collection<T> when an item is set in list;
        /// raises a CollectionChanged event to any listeners.
        /// 
        protected override void SetItem(int index, T item) 
        {
            CheckReentrancy(); 
            T originalItem = this[index]; 
            base.SetItem(index, item);
 
            OnPropertyChanged(IndexerName);
            OnCollectionChanged(NotifyCollectionChangedAction.Replace, originalItem, item, index);
        }
 
        /// 
        /// Called by base class ObservableCollection<T> when an item is to be moved within the list; 
        /// raises a CollectionChanged event to any listeners. 
        /// 
        protected virtual void MoveItem(int oldIndex, int newIndex) 
        {
            CheckReentrancy();

            T removedItem = this[oldIndex]; 

            base.RemoveItem(oldIndex); 
            base.InsertItem(newIndex, removedItem); 

            OnPropertyChanged(IndexerName); 
            OnCollectionChanged(NotifyCollectionChangedAction.Move, removedItem, newIndex, oldIndex);
        }

 
        /// 
        /// Raises a PropertyChanged event (per ). 
        ///  
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        { 
            if (PropertyChanged != null)
            {
                PropertyChanged(this, e);
            } 
        }
 
        ///  
        /// PropertyChanged event (per ).
        ///  
        [field:NonSerializedAttribute()]
        protected virtual event PropertyChangedEventHandler PropertyChanged;

        ///  
        /// Raise CollectionChanged event to any listeners.
        /// Properties/methods modifying this ObservableCollection will raise 
        /// a collection changed event through this virtual method. 
        /// 
        ///  
        /// When overriding this method, either call its base implementation
        /// or call  to guard against reentrant collection changes.
        /// 
        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
        {
            if (CollectionChanged != null) 
            { 
                using (BlockReentrancy())
                { 
                    CollectionChanged(this, e);
                }
            }
        } 

        ///  
        /// 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)); 
        ///         } 
        /// 
        ///  
        protected 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  
        protected void CheckReentrancy()
        {
            if (_monitor.Busy)
            { 
                // we can allow changes if there's only one listener - the problem
                // only arises if reentrant changes make the original event args 
                // invalid for later listeners.  This keeps existing code working 
                // (e.g. Selector.SelectedItems).
                if ((CollectionChanged != null) && (CollectionChanged.GetInvocationList().Length > 1)) 
                    throw new InvalidOperationException(SR.GetString(SR.ObservableCollectionReentrancyNotAllowed));
            }
        }
 
        #endregion Protected Methods
 
 
        //-----------------------------------------------------
        // 
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Methods
        ///  
        /// Helper to raise a PropertyChanged event  />). 
        /// 
        private void OnPropertyChanged(string propertyName) 
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }
 
        /// 
        /// Helper to raise CollectionChanged event to any listeners 
        ///  
        private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index)
        { 
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index));
        }

        ///  
        /// Helper to raise CollectionChanged event to any listeners
        ///  
        private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index, int oldIndex) 
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index, oldIndex)); 
        }

        /// 
        /// Helper to raise CollectionChanged event to any listeners 
        /// 
        private void OnCollectionChanged(NotifyCollectionChangedAction action, object oldItem, object newItem, int index) 
        { 
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem, index));
        } 

        /// 
        /// Helper to raise CollectionChanged event with action == Reset to any listeners
        ///  
        private void OnCollectionReset()
        { 
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
        }
        #endregion Private Methods 

        //-----------------------------------------------------
        //
        //  Private Types 
        //
        //------------------------------------------------------ 
 
        #region Private Types
 
        // this class helps prevent reentrant calls
        [Serializable()]
        [TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
        private class SimpleMonitor : IDisposable 
        {
            public void Enter() 
            { 
                ++ _busyCount;
            } 

            public void Dispose()
            {
                -- _busyCount; 
            }
 
            public bool Busy { get { return _busyCount > 0; } } 

            int _busyCount; 
        }

        #endregion Private Types
 
        //------------------------------------------------------
        // 
        //  Private Fields 
        //
        //----------------------------------------------------- 

        #region Private Fields

        private const string CountString = "Count"; 

        // This must agree with Binding.IndexerName.  It is declared separately 
        // here so as to avoid a dependency on PresentationFramework.dll. 
        private const string IndexerName = "Item[]";
 
        private SimpleMonitor _monitor = new SimpleMonitor();

        #endregion Private Fields
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) 2003 by Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: Implementation of an Collection implementing INotifyCollectionChanged 
//              to notify listeners of dynamic changes of the list.
// 
// See spec at http://avalon/connecteddata/Specs/Collection%20Interfaces.mht
//
// History:
//  11/22/2004 : [....] - created 
//
//--------------------------------------------------------------------------- 
 
using System;
using System.Collections; 
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Runtime.CompilerServices; 

namespace System.Collections.ObjectModel 
{ 
    /// 
    /// Implementation of a dynamic data collection based on generic Collection<T>, 
    /// implementing INotifyCollectionChanged to notify listeners
    /// when items get added, removed or the whole list is refreshed.
    /// 
    [Serializable()] 
    [TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
    public class ObservableCollection : Collection, INotifyCollectionChanged, INotifyPropertyChanged 
    { 
        //-----------------------------------------------------
        // 
        //  Constructors
        //
        //-----------------------------------------------------
 
        #region Constructors
        ///  
        /// Initializes a new instance of ObservableCollection that is empty and has default initial capacity. 
        /// 
        public ObservableCollection() : base() { } 

        /// 
        /// Initializes a new instance of the ObservableCollection class
        /// that contains elements copied from the specified list 
        /// 
        /// The list whose elements are copied to the new list. 
        ///  
        /// The elements are copied onto the ObservableCollection in the
        /// same order they are read by the enumerator of the list. 
        /// 
        ///  list is a null reference 
        public ObservableCollection(List list)
            : base((list != null) ? new List(list.Count) : list) 
        {
            // Workaround for VSWhidbey bug 562681 (tracked by Windows bug 1369339). 
            // We should be able to simply call the base(list) ctor.  But Collection 
            // doesn't copy the list (contrary to the documentation) - it uses the
            // list directly as its storage.  So we do the copying here. 
            //
            CopyFrom(list);
        }
 
        /// 
        /// Initializes a new instance of the ObservableCollection class that contains 
        /// elements copied from the specified collection and has sufficient capacity 
        /// to accommodate the number of elements copied.
        ///  
        /// The collection whose elements are copied to the new list.
        /// 
        /// The elements are copied onto the ObservableCollection in the
        /// same order they are read by the enumerator of the collection. 
        /// 
        ///  collection is a null reference  
        public ObservableCollection(IEnumerable collection) 
        {
            if (collection == null) 
                throw new ArgumentNullException("collection");

            CopyFrom(collection);
        } 

        private void CopyFrom(IEnumerable collection) 
        { 
            IList items = Items;
            if (collection != null && items != null) 
            {
                using (IEnumerator enumerator = collection.GetEnumerator())
                {
                    while (enumerator.MoveNext()) 
                    {
                        items.Add(enumerator.Current); 
                    } 
                }
            } 
        }

        #endregion Constructors
 

        //------------------------------------------------------ 
        // 
        //  Public Methods
        // 
        //-----------------------------------------------------

        #region Public Methods
 
        /// 
        /// Move item at oldIndex to newIndex. 
        ///  
        public void Move(int oldIndex, int newIndex)
        { 
            MoveItem(oldIndex, newIndex);
        }

        #endregion Public Methods 

 
        //------------------------------------------------------ 
        //
        //  Public Events 
        //
        //------------------------------------------------------

        #region Public Events 

        //----------------------------------------------------- 
        #region INotifyPropertyChanged implementation 

        ///  
        /// PropertyChanged event (per ).
        /// 
        event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
        { 
            add
            { 
                PropertyChanged += value; 
            }
            remove 
            {
                PropertyChanged -= value;
            }
        } 
        #endregion INotifyPropertyChanged implementation
 
 
        //------------------------------------------------------
        ///  
        /// Occurs when the collection changes, either by adding or removing an item.
        /// 
        /// 
        /// see  
        /// 
        [field:NonSerializedAttribute()] 
        public virtual event NotifyCollectionChangedEventHandler CollectionChanged; 

        #endregion Public Events 


        //-----------------------------------------------------
        // 
        //  Protected Methods
        // 
        //----------------------------------------------------- 

        #region Protected Methods 

        /// 
        /// Called by base class Collection<T> when the list is being cleared;
        /// raises a CollectionChanged event to any listeners. 
        /// 
        protected override void ClearItems() 
        { 
            CheckReentrancy();
            base.ClearItems(); 
            OnPropertyChanged(CountString);
            OnPropertyChanged(IndexerName);
            OnCollectionReset();
        } 

        ///  
        /// Called by base class Collection<T> when an item is removed from list; 
        /// raises a CollectionChanged event to any listeners.
        ///  
        protected override void RemoveItem(int index)
        {
            CheckReentrancy();
            T removedItem  = this[index]; 

            base.RemoveItem(index); 
 
            OnPropertyChanged(CountString);
            OnPropertyChanged(IndexerName); 
            OnCollectionChanged(NotifyCollectionChangedAction.Remove, removedItem, index);
        }

        ///  
        /// Called by base class Collection<T> when an item is added to list;
        /// raises a CollectionChanged event to any listeners. 
        ///  
        protected override void InsertItem(int index, T item)
        { 
            CheckReentrancy();
            base.InsertItem(index, item);

            OnPropertyChanged(CountString); 
            OnPropertyChanged(IndexerName);
            OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index); 
        } 

        ///  
        /// Called by base class Collection<T> when an item is set in list;
        /// raises a CollectionChanged event to any listeners.
        /// 
        protected override void SetItem(int index, T item) 
        {
            CheckReentrancy(); 
            T originalItem = this[index]; 
            base.SetItem(index, item);
 
            OnPropertyChanged(IndexerName);
            OnCollectionChanged(NotifyCollectionChangedAction.Replace, originalItem, item, index);
        }
 
        /// 
        /// Called by base class ObservableCollection<T> when an item is to be moved within the list; 
        /// raises a CollectionChanged event to any listeners. 
        /// 
        protected virtual void MoveItem(int oldIndex, int newIndex) 
        {
            CheckReentrancy();

            T removedItem = this[oldIndex]; 

            base.RemoveItem(oldIndex); 
            base.InsertItem(newIndex, removedItem); 

            OnPropertyChanged(IndexerName); 
            OnCollectionChanged(NotifyCollectionChangedAction.Move, removedItem, newIndex, oldIndex);
        }

 
        /// 
        /// Raises a PropertyChanged event (per ). 
        ///  
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        { 
            if (PropertyChanged != null)
            {
                PropertyChanged(this, e);
            } 
        }
 
        ///  
        /// PropertyChanged event (per ).
        ///  
        [field:NonSerializedAttribute()]
        protected virtual event PropertyChangedEventHandler PropertyChanged;

        ///  
        /// Raise CollectionChanged event to any listeners.
        /// Properties/methods modifying this ObservableCollection will raise 
        /// a collection changed event through this virtual method. 
        /// 
        ///  
        /// When overriding this method, either call its base implementation
        /// or call  to guard against reentrant collection changes.
        /// 
        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
        {
            if (CollectionChanged != null) 
            { 
                using (BlockReentrancy())
                { 
                    CollectionChanged(this, e);
                }
            }
        } 

        ///  
        /// 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)); 
        ///         } 
        /// 
        ///  
        protected 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  
        protected void CheckReentrancy()
        {
            if (_monitor.Busy)
            { 
                // we can allow changes if there's only one listener - the problem
                // only arises if reentrant changes make the original event args 
                // invalid for later listeners.  This keeps existing code working 
                // (e.g. Selector.SelectedItems).
                if ((CollectionChanged != null) && (CollectionChanged.GetInvocationList().Length > 1)) 
                    throw new InvalidOperationException(SR.GetString(SR.ObservableCollectionReentrancyNotAllowed));
            }
        }
 
        #endregion Protected Methods
 
 
        //-----------------------------------------------------
        // 
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Methods
        ///  
        /// Helper to raise a PropertyChanged event  />). 
        /// 
        private void OnPropertyChanged(string propertyName) 
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }
 
        /// 
        /// Helper to raise CollectionChanged event to any listeners 
        ///  
        private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index)
        { 
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index));
        }

        ///  
        /// Helper to raise CollectionChanged event to any listeners
        ///  
        private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index, int oldIndex) 
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index, oldIndex)); 
        }

        /// 
        /// Helper to raise CollectionChanged event to any listeners 
        /// 
        private void OnCollectionChanged(NotifyCollectionChangedAction action, object oldItem, object newItem, int index) 
        { 
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem, index));
        } 

        /// 
        /// Helper to raise CollectionChanged event with action == Reset to any listeners
        ///  
        private void OnCollectionReset()
        { 
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
        }
        #endregion Private Methods 

        //-----------------------------------------------------
        //
        //  Private Types 
        //
        //------------------------------------------------------ 
 
        #region Private Types
 
        // this class helps prevent reentrant calls
        [Serializable()]
        [TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
        private class SimpleMonitor : IDisposable 
        {
            public void Enter() 
            { 
                ++ _busyCount;
            } 

            public void Dispose()
            {
                -- _busyCount; 
            }
 
            public bool Busy { get { return _busyCount > 0; } } 

            int _busyCount; 
        }

        #endregion Private Types
 
        //------------------------------------------------------
        // 
        //  Private Fields 
        //
        //----------------------------------------------------- 

        #region Private Fields

        private const string CountString = "Count"; 

        // This must agree with Binding.IndexerName.  It is declared separately 
        // here so as to avoid a dependency on PresentationFramework.dll. 
        private const string IndexerName = "Item[]";
 
        private SimpleMonitor _monitor = new SimpleMonitor();

        #endregion Private Fields
    } 
}

// 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