ObservableCollection.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 / Base / System / Collections / ObjectModel / ObservableCollection.cs / 1 / 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.Windows; 

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()] 
    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.Get(SRID.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()]
        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.Windows; 

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()] 
    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.Get(SRID.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()]
        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