BindingList.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / CompMod / System / ComponentModel / BindingList.cs / 1 / BindingList.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Scope="type", Target="System.ComponentModel.BindingList`1")]
 
namespace System.ComponentModel 
{
    using System; 
    using System.Reflection;
    using System.Collections;
    using System.Collections.ObjectModel;
    using System.Collections.Generic; 
    using System.ComponentModel;
    using System.Diagnostics; 
    using System.Security.Permissions; 
    using CodeAccessPermission = System.Security.CodeAccessPermission;
 
    /// 
    /// 
    /// 
    [HostProtection(SharedState = true)] 
    [Serializable]
    public class BindingList : Collection, IBindingList, ICancelAddNew, IRaiseItemChangedEvents 
    { 
        private int addNewPos = -1;
        private bool raiseListChangedEvents = true; 
        private bool raiseItemChangedEvents = false;

        [NonSerialized()]
        private PropertyDescriptorCollection itemTypeProperties = null; 

        [NonSerialized()] 
        private PropertyChangedEventHandler propertyChangedEventHandler = null; 

        [NonSerialized()] 
        private AddingNewEventHandler onAddingNew;

        [NonSerialized()]
        private ListChangedEventHandler onListChanged; 

        [NonSerialized()] 
        private int lastChangeIndex = -1; 

        private bool allowNew = true; 
        private bool allowEdit = true;
        private bool allowRemove = true;
        private bool userSetAllowNew = false;
 
        #region Constructors
 
        ///  
        /// 
        ///     Default constructor. 
        /// 
        public BindingList() : base() {
            Initialize();
        } 

        ///  
        ///  
        ///     Constructor that allows substitution of the inner list with a custom list.
        ///  
        public BindingList(IList list) : base(list) {
            Initialize();
        }
 
        private void Initialize() {
            // Set the default value of AllowNew based on whether type T has a default constructor 
            this.allowNew = ItemTypeHasDefaultConstructor; 

            // Check for INotifyPropertyChanged 
            if (typeof(INotifyPropertyChanged).IsAssignableFrom(typeof(T))) {
                // Supports INotifyPropertyChanged
                this.raiseItemChangedEvents = true;
 
                // Loop thru the items already in the collection and hook their change notification.
                foreach (T item in this.Items) { 
                    HookPropertyChanged(item); 
                }
            } 
        }

        private bool ItemTypeHasDefaultConstructor {
            get { 
                Type itemType = typeof(T);
 
                if (itemType.IsPrimitive) { 
                    return true;
                } 

                if (itemType.GetConstructor(BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, new Type[0], null) != null) {
                    return true;
                } 

                return false; 
            } 
        }
 
        #endregion

        #region AddingNew event
 
        /// 
        ///  
        ///     Event that allows a custom item to be provided as the new item added to the list by AddNew(). 
        /// 
        public event AddingNewEventHandler AddingNew { 
            add {
                bool allowNewWasTrue = AllowNew;
                onAddingNew += value;
                if (allowNewWasTrue != AllowNew) { 
                    FireListChanged(ListChangedType.Reset, -1);
                } 
            } 
            remove {
                bool allowNewWasTrue = AllowNew; 
                onAddingNew -= value;
                if (allowNewWasTrue != AllowNew) {
                    FireListChanged(ListChangedType.Reset, -1);
                } 
            }
        } 
 
        /// 
        ///  
        ///     Raises the AddingNew event.
        /// 
        protected virtual void OnAddingNew(AddingNewEventArgs e) {
            if (onAddingNew != null) { 
                onAddingNew(this, e);
            } 
        } 

        // Private helper method 
        private object FireAddingNew() {
            AddingNewEventArgs e = new AddingNewEventArgs(null);
            OnAddingNew(e);
            return e.NewObject; 
        }
 
        #endregion 

        #region ListChanged event 

        /// 
        /// 
        ///     Event that reports changes to the list or to items in the list. 
        /// 
        public event ListChangedEventHandler ListChanged { 
            add { 
                onListChanged += value;
            } 
            remove {
                onListChanged -= value;
            }
        } 

        ///  
        ///  
        ///     Raises the ListChanged event.
        ///  
        protected virtual void OnListChanged(ListChangedEventArgs e) {
            if (onListChanged != null) {
                onListChanged(this, e);
            } 
        }
 
        /// 
        /// 
        ///  
        public void ResetBindings() {
            FireListChanged(ListChangedType.Reset, -1); 
        } 

        ///  
        /// 
        /// 
        public void ResetItem(int position) {
            FireListChanged(ListChangedType.ItemChanged, position); 
        }
 
        // Private helper method 
        private void FireListChanged(ListChangedType type, int index) {
            if (this.raiseListChangedEvents) { 
                OnListChanged(new ListChangedEventArgs(type, index));
            }
        }
 
        #endregion
 
        #region Collection overrides 

        // Collection funnels all list changes through the four virtual methods below. 
        // We override these so that we can commit any pending new item and fire the proper ListChanged events.

        protected override void ClearItems() {
            EndNew(addNewPos); 

            if (this.raiseItemChangedEvents) { 
                foreach (T item in this.Items) { 
                    UnhookPropertyChanged(item);
                } 
            }

            base.ClearItems();
            FireListChanged(ListChangedType.Reset, -1); 
        }
 
        protected override void InsertItem(int index, T item) { 
            EndNew(addNewPos);
            base.InsertItem(index, item); 

            if (this.raiseItemChangedEvents) {
                HookPropertyChanged(item);
            } 

            FireListChanged(ListChangedType.ItemAdded, index); 
        } 

        protected override void RemoveItem(int index) { 
            // Need to all RemoveItem if this on the AddNew item
            if (!this.allowRemove && !(this.addNewPos >= 0 && this.addNewPos == index)) {
                throw new NotSupportedException();
            } 

            EndNew(addNewPos); 
 
            if (this.raiseItemChangedEvents) {
                UnhookPropertyChanged(this[index]); 
            }

            base.RemoveItem(index);
            FireListChanged(ListChangedType.ItemDeleted, index); 
        }
 
        protected override void SetItem(int index, T item) { 

            if (this.raiseItemChangedEvents) { 
                UnhookPropertyChanged(this[index]);
            }

            base.SetItem(index, item); 

            if (this.raiseItemChangedEvents) { 
                HookPropertyChanged(item); 
            }
 
            FireListChanged(ListChangedType.ItemChanged, index);
        }

        #endregion 

        #region ICancelAddNew interface 
 
        /// 
        ///  
        ///     If item added using AddNew() is still cancellable, then remove that item from the list.
        /// 
        public virtual void CancelNew(int itemIndex)
        { 
            if (addNewPos >= 0 && addNewPos == itemIndex) {
                RemoveItem(addNewPos); 
                addNewPos = -1; 
            }
        } 

        /// 
        /// 
        ///     If item added using AddNew() is still cancellable, then commit that item. 
        /// 
        public virtual void EndNew(int itemIndex) 
        { 
            if (addNewPos >= 0 && addNewPos == itemIndex) {
                addNewPos = -1; 
            }
        }

        #endregion 

        #region IBindingList interface 
 
        /// 
        ///  
        ///     Adds a new item to the list. Calls  to create and add the item.
        ///
        ///     Add operations are cancellable via the  interface. The position of the
        ///     new item is tracked until the add operation is either cancelled by a call to , 
        ///     explicitly commited by a call to , or implicitly commmited some other operation
        ///     that changes the contents of the list (such as an Insert or Remove). When an add operation is 
        ///     cancelled, the new item is removed from the list. 
        /// 
        public T AddNew() { 
            return (T)((this as IBindingList).AddNew());
        }

        object IBindingList.AddNew() { 
            // Create new item and add it to list
            object newItem = AddNewCore(); 
 
            // Record position of new item (to support cancellation later on)
            addNewPos = (newItem != null) ? IndexOf((T) newItem) : -1; 

            // Return new item to caller
            return newItem;
        } 

        private bool AddingNewHandled { 
            get { 
                return onAddingNew != null && onAddingNew.GetInvocationList().Length > 0;
            } 
        }

        /// 
        ///  
        ///     Creates a new item and adds it to the list.
        /// 
        ///     The base implementation raises the AddingNew event to allow an event handler to 
        ///     supply a custom item to add to the list. Otherwise an item of type T is created.
        ///     The new item is then added to the end of the list. 
        /// 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2113:SecureLateBindingMethods")]
        protected virtual object AddNewCore() {
            // Allow event handler to supply the new item for us 
            object newItem = FireAddingNew();
 
            // If event hander did not supply new item, create one ourselves 
            if (newItem == null) {
 
                Type type = typeof(T);
                newItem = SecurityUtils.SecureCreateInstance(type);
            }
 
            // Add item to end of list. Note: If event handler returned an item not of type T,
            // the cast below will trigger an InvalidCastException. This is by design. 
            Add((T) newItem); 

            // Return new item to caller 
            return newItem;
        }

        ///  
        /// 
        ///  
        public bool AllowNew { 
            get {
                //If the user set AllowNew, return what they set.  If we have a default constructor, allowNew will be 
                //true and we should just return true.
                if (userSetAllowNew || allowNew)
                {
                    return this.allowNew; 
                }
                //Even if the item doesn't have a default constructor, the user can hook AddingNew to provide an item. 
                //If there's a handler for this, we should allow new. 
                return AddingNewHandled;
            } 
            set {
                bool oldAllowNewValue = AllowNew;
                userSetAllowNew = true;
                //Note that we don't want to set allowNew only if AllowNew didn't match value, 
                //since AllowNew can depend on onAddingNew handler
                this.allowNew = value; 
                if (oldAllowNewValue != value) { 
                    FireListChanged(ListChangedType.Reset, -1);
                } 
            }
        }

        /* private */ bool IBindingList.AllowNew { 
            get {
                return AllowNew; 
            } 
        }
 
        /// 
        /// 
        /// 
        public bool AllowEdit { 
            get {
                return this.allowEdit; 
            } 
            set {
                if (this.allowEdit != value) { 
                    this.allowEdit = value;
                    FireListChanged(ListChangedType.Reset, -1);
                }
            } 
        }
 
        /* private */ bool IBindingList.AllowEdit { 
            get {
                return AllowEdit; 
            }
        }

        ///  
        /// 
        ///  
        public bool AllowRemove { 
            get {
                return this.allowRemove; 
            }
            set {
                if (this.allowRemove != value) {
                    this.allowRemove = value; 
                    FireListChanged(ListChangedType.Reset, -1);
                } 
            } 
        }
 
        /* private */ bool IBindingList.AllowRemove {
            get {
                return AllowRemove;
            } 
        }
 
        bool IBindingList.SupportsChangeNotification { 
            get {
                return SupportsChangeNotificationCore; 
            }
        }

        protected virtual bool SupportsChangeNotificationCore { 
            get {
                return true; 
            } 
        }
 
        bool IBindingList.SupportsSearching {
            get {
                return SupportsSearchingCore;
            } 
        }
 
        protected virtual bool SupportsSearchingCore { 
            get {
                return false; 
            }
        }

        bool IBindingList.SupportsSorting { 
            get {
                return SupportsSortingCore; 
            } 
        }
 
        protected virtual bool SupportsSortingCore {
            get {
                return false;
            } 
        }
 
        bool IBindingList.IsSorted { 
            get {
                return IsSortedCore; 
            }
        }

        protected virtual bool IsSortedCore { 
            get {
                return false; 
            } 
        }
 
        PropertyDescriptor IBindingList.SortProperty {
            get {
                return SortPropertyCore;
            } 
        }
 
        protected virtual PropertyDescriptor SortPropertyCore { 
            get {
                return null; 
            }
        }

        ListSortDirection IBindingList.SortDirection { 
            get {
                return SortDirectionCore; 
            } 
        }
 
        protected virtual ListSortDirection SortDirectionCore {
            get {
                return ListSortDirection.Ascending;
            } 
        }
 
        void IBindingList.ApplySort(PropertyDescriptor prop, ListSortDirection direction) { 
            ApplySortCore(prop, direction);
        } 

        protected virtual void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction) {
            throw new NotSupportedException();
        } 

        void IBindingList.RemoveSort() { 
            RemoveSortCore(); 
        }
 
        protected virtual void RemoveSortCore() {
            throw new NotSupportedException();
        }
 
        int IBindingList.Find(PropertyDescriptor prop, object key) {
            return FindCore(prop, key); 
        } 

        protected virtual int FindCore(PropertyDescriptor prop, object key) { 
            throw new NotSupportedException();
        }

        void IBindingList.AddIndex(PropertyDescriptor prop) { 
            // Not supported
        } 
 
        void IBindingList.RemoveIndex(PropertyDescriptor prop) {
            // Not supported 
        }

        #endregion
 
        #region Property Change Support
 
        private void HookPropertyChanged(T item) { 
            INotifyPropertyChanged inpc = (item as INotifyPropertyChanged);
 
            // Note: inpc may be null if item is null, so always check.
            if (null != inpc) {
                if (propertyChangedEventHandler == null) {
                    propertyChangedEventHandler = new PropertyChangedEventHandler(Child_PropertyChanged); 
                }
                inpc.PropertyChanged += propertyChangedEventHandler; 
            } 
        }
 
        private void UnhookPropertyChanged(T item) {
            INotifyPropertyChanged inpc = (item as INotifyPropertyChanged);

            // Note: inpc may be null if item is null, so always check. 
            if (null != inpc && null != propertyChangedEventHandler) {
                inpc.PropertyChanged -= propertyChangedEventHandler; 
            } 
        }
 
        void Child_PropertyChanged(object sender, PropertyChangedEventArgs e) {
            if (this.RaiseListChangedEvents) {
                if (sender == null || e == null || string.IsNullOrEmpty(e.PropertyName)) {
                    // Fire reset event (per INotifyPropertyChanged spec) 
                    ResetBindings();
                } 
                else { 
                    // The change event is broken should someone pass an item to us that is not
                    // of type T.  Still, if they do so, detect it and ignore.  It is an incorrect 
                    // and rare enough occurrence that we do not want to slow the mainline path
                    // with "is" checks.
                    T item;
 
                    try {
                        item = (T)sender; 
                    } 
                    catch(InvalidCastException) {
                        ResetBindings(); 
                        return;
                    }

                    // Find the position of the item.  This should never be -1.  If it is, 
                    // somehow the item has been removed from our list without our knowledge.
                    int pos = lastChangeIndex; 
 
                    if (pos < 0 || pos >= Count || !this[pos].Equals(item)) {
                        pos = this.IndexOf(item); 
                        lastChangeIndex = pos;
                    }

                    if (pos == -1) { 
                        Debug.Fail("Item is no longer in our list but we are still getting change notifications.");
                        UnhookPropertyChanged(item); 
                        ResetBindings(); 
                    }
                    else { 
                        // Get the property descriptor
                        if (null == this.itemTypeProperties) {
                            // Get Shape
                            itemTypeProperties = TypeDescriptor.GetProperties(typeof(T)); 
                            Debug.Assert(itemTypeProperties != null);
                        } 
 
                        PropertyDescriptor pd = itemTypeProperties.Find(e.PropertyName, true);
 
                        // Create event args.  If there was no matching property descriptor,
                        // we raise the list changed anyway.
                        ListChangedEventArgs args = new ListChangedEventArgs(ListChangedType.ItemChanged, pos, pd);
 
                        // Fire the ItemChanged event
                        OnListChanged(args); 
                    } 
                }
            } 
        }

        #endregion
 
        #region IRaiseItemChangedEvents interface
 
        ///  
        /// 
        ///     Returns false to indicate that BindingList does NOT raise ListChanged events 
        ///     of type ItemChanged as a result of property changes on individual list items
        ///     unless those items support INotifyPropertyChanged
        /// 
        bool IRaiseItemChangedEvents.RaisesItemChangedEvents { 
            get {
                return this.raiseItemChangedEvents; 
            } 
        }
 
        #endregion

    }
} 


                        

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