ObservableCollection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / 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 [....]/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.
            // 
            IList items = Items;
            if (list != null && items != null)
            {
                using (IEnumerator enumerator = list.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  
        ///  
        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 ). 
        /// 
        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