BindingSource.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / WinForms / Managed / System / WinForms / BindingSource.cs / 1 / BindingSource.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope="member", Target="System.Windows.Forms.BindingSource.System.ComponentModel.ISupportInitialize.EndInit():System.Void")] 
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope="member", Target="System.Windows.Forms.BindingSource.System.ComponentModel.ICancelAddNew.CancelNew(System.Int32):System.Void")] 
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope="member", Target="System.Windows.Forms.BindingSource.System.ComponentModel.ICancelAddNew.EndNew(System.Int32):System.Void")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope="member", Target="System.Windows.Forms.BindingSource.System.ComponentModel.ISupportInitialize.BeginInit():System.Void")] 
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope="member", Target="System.Windows.Forms.BindingSource.System.ComponentModel.ISupportInitializeNotification.get_IsInitialized():System.Boolean")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope="member", Target="System.Windows.Forms.BindingSource.System.ComponentModel.IBindingList.AddIndex(System.ComponentModel.PropertyDescriptor):System.Void")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope="member", Target="System.Windows.Forms.BindingSource.System.ComponentModel.ISupportInitializeNotification.add_Initialized(System.EventHandler):System.Void")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope="member", Target="System.Windows.Forms.BindingSource.System.ComponentModel.ISupportInitializeNotification.remove_Initialized(System.EventHandler):System.Void")] 
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope="member", Target="System.Windows.Forms.BindingSource.System.ComponentModel.IBindingList.RemoveIndex(System.ComponentModel.PropertyDescriptor):System.Void")]
 
namespace System.Windows.Forms { 
    using System;
    using System.Collections; 
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Drawing; 
    using System.Globalization;
    using System.Reflection; 
    using System.Security; 
    using System.Security.Permissions;
    using System.Text; 

    [
    DefaultProperty("DataSource"),
    DefaultEvent("CurrentChanged"), 
    ComplexBindingProperties("DataSource", "DataMember"),
    Designer("System.Windows.Forms.Design.BindingSourceDesigner, " + AssemblyRef.SystemDesign), 
    SRDescription(SR.DescriptionBindingSource), 
    System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1035:ICollectionImplementationsHaveStronglyTypedMembers"), // ICollection.CopyTo: Its just a wrapper class, it doesn't have a specific member type
    System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix"), // ICollection: We don't want class name to have to end in 'Collection' 
    System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1039:ListsAreStronglyTyped"), // IList.Add: Its just a wrapper class, it doesn't have a specific member type
    ]
    ///  relatedBindingSources; 

        // Support for user-overriding of the AllowNew property
        private bool allowNewIsSet       = false;
        private bool allowNewSetValue    = true; 

        // Support for property change event hooking on list items 
        private object currentItemHookedForItemChange = null; 
        private object lastCurrentItem = null;
        private EventHandler listItemPropertyChangedHandler; 

        // State data
        private int  addNewPos = -1;
        private bool initializing = false; 
        private bool needToSetList = false;
        private bool recursionDetectionFlag = false; 
        private bool innerListChanging = false; 
        private bool endingEdit = false;
 

        ///////////////////////////////////////////////////////////////////////////////
        //
        // Constructors 
        //
        /////////////////////////////////////////////////////////////////////////////// 
 
        /// (); 
            } 

            // Look for an existing binding source that uses this data member, and return that 
            foreach (string key in this.relatedBindingSources.Keys) {
                if (String.Equals(key, dataMember, StringComparison.OrdinalIgnoreCase)) {
                    return this.relatedBindingSources[key];
                } 
            }
 
            // Otherwise create the related binding source, cache it, and return it 
            BindingSource bs = new BindingSource(this, dataMember);
            this.relatedBindingSources[dataMember] = bs; 
            return bs;
        }

        ///  
        [Browsable(false)]
        public object Current { 
            get { 
                return currencyManager.Count > 0 ? currencyManager.Current : null;
            } 
        }

        [
        SRCategory(SR.CatData), 
        DefaultValue(""),
        RefreshProperties(RefreshProperties.Repaint), 
        Editor("System.Windows.Forms.Design.DataMemberListEditor, " + AssemblyRef.SystemDesign, typeof(System.Drawing.Design.UITypeEditor)), 
        SRDescription(SR.BindingSourceDataMemberDescr)
        ] 
        ///  
        [Browsable(false)] 
        public bool IsBindingSuspended {
            get { 
                return currencyManager.IsBindingSuspended;
            }
        }
 
        [Browsable(false)]
        /// 
        public string Sort { 
            get { 
                return this.sort;
            } 
            set {
                this.sort = value;
                InnerListSort = value;
            } 
        }
 
        #region Events 
        ///////////////////////////////////////////////////////////////////////////////
        // 
        // Events
        //
        ///////////////////////////////////////////////////////////////////////////////
 
        [
        SRCategory(SR.CatData), 
        SRDescription(SR.BindingSourceAddingNewEventHandlerDescr) 
        ]
        ///  
        public event AddingNewEventHandler AddingNew {
            add {
                Events.AddHandler(EVENT_ADDINGNEW, value);
            } 
            remove {
                Events.RemoveHandler(EVENT_ADDINGNEW, value); 
            } 
        }
 
        /// 
        [
        SRCategory(SR.CatData),
        SRDescription(SR.BindingSourceBindingCompleteEventHandlerDescr) 
        ]
        public event BindingCompleteEventHandler BindingComplete { 
            add { 
                Events.AddHandler(EVENT_BINDINGCOMPLETE, value);
            } 
            remove {
                Events.RemoveHandler(EVENT_BINDINGCOMPLETE, value);
            }
        } 

        [ 
        SRCategory(SR.CatData), 
        SRDescription(SR.BindingSourceDataErrorEventHandlerDescr)
        ] 
        /// 
        public event BindingManagerDataErrorEventHandler DataError {
            add {
                Events.AddHandler(EVENT_DATAERROR, value); 
            }
            remove { 
                Events.RemoveHandler(EVENT_DATAERROR, value); 
            }
        } 

        [
        SRCategory(SR.CatData),
        SRDescription(SR.BindingSourceDataSourceChangedEventHandlerDescr) 
        ]
        ///  
        public event EventHandler DataSourceChanged { 
            add {
                Events.AddHandler(EVENT_DATASOURCECHANGED, value); 
            }
            remove {
                Events.RemoveHandler(EVENT_DATASOURCECHANGED, value);
            } 
        }
 
        [ 
        SRCategory(SR.CatData),
        SRDescription(SR.BindingSourceDataMemberChangedEventHandlerDescr) 
        ]
        /// 
        public event EventHandler DataMemberChanged {
            add { 
                Events.AddHandler(EVENT_DATAMEMBERCHANGED, value);
            } 
            remove { 
                Events.RemoveHandler(EVENT_DATAMEMBERCHANGED, value);
            } 
        }

        [
        SRCategory(SR.CatData), 
        SRDescription(SR.BindingSourceCurrentChangedEventHandlerDescr)
        ] 
        ///  
        public event EventHandler CurrentChanged {
            add { 
                Events.AddHandler(EVENT_CURRENTCHANGED, value);
            }
            remove {
                Events.RemoveHandler(EVENT_CURRENTCHANGED, value); 
            }
        } 
 
        [
        SRCategory(SR.CatData), 
        SRDescription(SR.BindingSourceCurrentItemChangedEventHandlerDescr)
        ]
        /// 
        public event EventHandler CurrentItemChanged { 
            add {
                Events.AddHandler(EVENT_CURRENTITEMCHANGED, value); 
            } 
            remove {
                Events.RemoveHandler(EVENT_CURRENTITEMCHANGED, value); 
            }
        }

        [ 
        SRCategory(SR.CatData),
        SRDescription(SR.BindingSourceListChangedEventHandlerDescr) 
        ] 
        /// 
        public event ListChangedEventHandler ListChanged { 
            add {
                Events.AddHandler(EVENT_LISTCHANGED, value);
            }
            remove { 
                Events.RemoveHandler(EVENT_LISTCHANGED, value);
            } 
        } 

        [ 
        SRCategory(SR.CatData),
        SRDescription(SR.BindingSourcePositionChangedEventHandlerDescr)
        ]
        ///  
        public event EventHandler PositionChanged {
            add { 
                Events.AddHandler(EVENT_POSITIONCHANGED, value); 
            }
            remove { 
                Events.RemoveHandler(EVENT_POSITIONCHANGED, value);
            }
        }
        #endregion Events 

        #region Methods 
        /////////////////////////////////////////////////////////////////////////////// 
        //
        // Methods 
        //
        ///////////////////////////////////////////////////////////////////////////////

        /* CUT: 

        // 
        // AutoSetDataMember() 
        //
        // Used when data source changes. If data member is not set, and the data source 
        // is a list of lists, arbitrarily point the data member at one of these lists.
        //
        private void AutoSetDataMember() {
            // Data member already assigned! 
            if (!String.IsNullOrEmpty(this.dataMember)) {
                return; 
            } 

            // Get the list of lists 
            IListSource listSource = this.dataSource as IListSource;

            // Not a list of lists!
            if (listSource == null || !listSource.ContainsListCollection) { 
                return;
            } 
 
            // Get properties of data source
            PropertyDescriptorCollection props = ListBindingHelper.GetListItemProperties(listSource); 

            // Walk properties of data source, looking for one that returns IList (but ignoring ones that return Array)
            for (int i = 0; i < props.Count; ++i) {
                PropertyDescriptor prop = props[i]; 

                if (typeof(IList).IsAssignableFrom(prop.PropertyType) && !typeof(Array).IsAssignableFrom(prop.PropertyType)) { 
                    // Bingo - got one! 
                    this.dataMember = prop.Name;
                    OnDataMemberChanged(EventArgs.Empty); 
                    break;
                }
            }
        } 

        */ 
 
        private static string BuildSortString(ListSortDescriptionCollection sortsColln) {
                if (sortsColln == null) { 
                    return String.Empty;
                }

                StringBuilder sb = new StringBuilder(sortsColln.Count); 

                for (int i = 0; i < sortsColln.Count; ++i) { 
                    sb.Append(sortsColln[i].PropertyDescriptor.Name + 
                              ((sortsColln[i].SortDirection == ListSortDirection.Ascending) ? " ASC" : " DESC") +
                              ((i < sortsColln.Count - 1) ? "," : String.Empty)); 
                }

                return sb.ToString();
        } 

        ///  
        public void CancelEdit() { 
            currencyManager.CancelCurrentEdit();
        } 

        // Walks the BindingSource::DataSource chain until
        // 1. there is a break in the chain ( BindingSource::DataSource is not a BindingSource ), or
        // 2. detects a cycle in the chain. 
        // If a cycle is detected we throw the BindingSourceRecursionDetected exception
        private void ThrowIfBindingSourceRecursionDetected(object newDataSource) { 
            BindingSource bindingSource = newDataSource as BindingSource; 

            while (bindingSource != null) { 
                if (bindingSource == this) {
                    throw new InvalidOperationException(SR.GetString(SR.BindingSourceRecursionDetected));
                }
                bindingSource = bindingSource.DataSource as BindingSource; 
            }
        } 
 
        private void ClearInvalidDataMember() {
            if (!IsDataMemberValid()) { 
                this.dataMember = "";
                OnDataMemberChanged(EventArgs.Empty);
            }
        } 

        // Creates an instance of BindingList where T is only known at run time, not compile time 
        private static IList CreateBindingList(Type type) { 
            Type genericType = typeof(BindingList<>);
            Type bindingType = genericType.MakeGenericType(new Type[] { type }); 

            return (IList) SecurityUtils.SecureCreateInstance(bindingType);
        }
 
        // Create an object of the given type. Throw an exception if this fails.
        private static object CreateInstanceOfType(Type type) { 
            object instancedObject = null; 
            Exception instanceException = null;
 
            try {
                instancedObject = SecurityUtils.SecureCreateInstance(type);
            }
            catch (TargetInvocationException ex) { 
                instanceException = ex; // Default ctor threw an exception
            } 
            catch (MethodAccessException ex) { 
                instanceException = ex; // Default ctor was not public
            } 
            catch (MissingMethodException ex) {
                instanceException = ex; // No default ctor defined
            }
 
            if (instanceException != null) {
                throw new NotSupportedException(SR.GetString(SR.BindingSourceInstanceError), instanceException); 
            } 

            return instancedObject; 
        }

        private void CurrencyManager_PositionChanged(object sender, EventArgs e) {
            Debug.Assert(sender == this.currencyManager, "only receive notifications from the currency manager"); 
            OnPositionChanged(e);
        } 
 
        private void CurrencyManager_CurrentChanged(object sender, EventArgs e) {
            OnCurrentChanged(EventArgs.Empty); 
        }

        private void CurrencyManager_CurrentItemChanged(object sender, EventArgs e) {
            OnCurrentItemChanged(EventArgs.Empty); 
        }
 
        private void CurrencyManager_BindingComplete(object sender, BindingCompleteEventArgs e) { 
            OnBindingComplete(e);
        } 

        private void CurrencyManager_DataError(object sender, BindingManagerDataErrorEventArgs e) {
            OnDataError(e);
        } 

        ///  
        ///     Unhook BindingSource from its data source, since the data source could be some 
        ///     global object who's lifetime exceeds the lifetime of the parent form. Otherwise
        ///     the BindingSource (and any components bound through it) will end up in limbo, 
        ///     still processing list change events, etc. And when unhooking from the data source,
        ///     take care not to trigger any events that could confuse compoents bound to us.
        /// 
        protected override void Dispose(bool disposing) { 
            if (disposing) {
                UnwireDataSource(); 
                UnwireInnerList(); 
                UnhookItemChangedEventsForOldCurrent();
                UnwireCurrencyManager(this.currencyManager); 
                this.dataSource = null;
                this.sort = null;
                this.dataMember = null;
                this._innerList = null; 
                this.isBindingList = false;
                this.needToSetList = true; 
                this.raiseListChangedEvents = false; 
            }
            disposedOrFinalized = true; 
            base.Dispose(disposing);
        }

        ///  
        public void EndEdit() {
            if (endingEdit) { 
                return; 
            }
            try { 
                endingEdit = true;
                currencyManager.EndCurrentEdit();
            }
            finally { 
                endingEdit = false;
            } 
        } 

        // 
        // EnsureInnerList()
        //
        // Ensures that the inner list has been set up. Handles the case of ResetList() being called during
        // initialization, which sets a flag to defer ResetList() work until after initialization is complete. 
        //
        private void EnsureInnerList() { 
            if (!this.initializing && needToSetList) { 
                needToSetList = false;
                ResetList(); 
            }
        }

        // 
        // Find()
        // 
        // Overload of IBindingList.Find that takes a string instead of a property descriptor (for convenience). 
        //
        public int Find(String propertyName, object key) { 
            PropertyDescriptor pd = (itemShape == null) ? null : itemShape.Find(propertyName, true);

            if (pd == null) {
                throw new System.ArgumentException(SR.GetString(SR.DataSourceDataMemberPropNotFound, propertyName)); 
            }
 
            return (this as IBindingList).Find(pd, key); 
        }
 
        //
        // GetListFromType()
        //
        // Given a type, create a list based on that type. If the type represents a list type, 
        // we create an instance of that type (or throw if we cannot instance that type).
        // Otherwise we assume the type represents the item type, in which case we create 
        // a typed BindingList of that item type. 
        //
 
        private static IList GetListFromType(Type type) {
            IList list = null;

            if (typeof(ITypedList).IsAssignableFrom(type) && typeof(IList).IsAssignableFrom(type)) { 
                list = CreateInstanceOfType(type) as IList;
            } 
            else if (typeof(IListSource).IsAssignableFrom(type)) { 
                list = (CreateInstanceOfType(type) as IListSource).GetList();
            } 
            else {
                list = CreateBindingList(ListBindingHelper.GetListItemType(type));
            }
 
            return list;
        } 
 
        //
        // GetListFromEnumerable() 
        //
        // Creates a list based on an enumerable object. We rip through the enumerable,
        // extract all its items, and stuff these items into a typed BindingList, using
        // the type of the first item to determine the type of the list. 
        //
        private static IList GetListFromEnumerable(IEnumerable enumerable) { 
            IList list = null; 

            foreach (object item in enumerable) { 
                if (list == null) {
                    list = CreateBindingList(item.GetType());
                }
 
                list.Add(item);
            } 
 
            return list;
        } 

        //
        // IsDataMemberValid()
        // 
        // Used when we change data sources or when the properties of the current data source change.
        // Decides whether this would be a good time to blow away the data member field, since it 
        // might not refer to a valid data source property any more. 
        //
        private bool IsDataMemberValid() { 
            // Don't mess with things during initialization because the data
            // member property can get set before the data source property.
            if (this.initializing) {
                return true; 
            }
 
            // If data member has not been specified, leave the data member property alone 
            if (String.IsNullOrEmpty(this.dataMember)) {
                return true; 
            }

            // See if data member corresponds to a valid property on the specified data source
            PropertyDescriptorCollection dsProps = ListBindingHelper.GetListItemProperties(this.dataSource); 
            PropertyDescriptor dmProp = dsProps[this.dataMember];
            if (dmProp != null) { 
                return true; 
            }
 
            return false;
        }

        private void InnerList_ListChanged(object sender, ListChangedEventArgs e) { 
            // Set recursive flag - see VSWhidbey 455276
            // Basically, we can have computed columns that cause our parent 
            // to change when our list changes.  This can cause recursion because we update 
            // when our parent updates which then causes our parent to update which
            // then causes us to update which then causes our parent to update which 
            // then causes us to update which then causes our parent to update...
            if (!this.innerListChanging) {
                try {
                    this.innerListChanging = true; 
                    OnListChanged(e);
                } 
                finally { 
                    this.innerListChanging = false;
                } 
            }
        }

        private void ListItem_PropertyChanged(object sender, EventArgs e) { 
            int index;
 
            // Performance: If the item that changed is the current item, we can avoid a potentially expensive call to IndexOf() 
            if (sender == currentItemHookedForItemChange) {
                index = this.Position; 
                Debug.Assert(index >= 0, "BindingSource.ListItem_PropertyChanged - no current item.");
                Debug.Assert(index == ((IList) this).IndexOf(sender), "BindingSource.ListItem_PropertyChanged - unexpected current item.");
            }
            else { 
                index = ((IList) this).IndexOf(sender);
            } 
            OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, index)); 
        }
 
        /// 
        public void MoveFirst() {
            Position = 0;
        } 

        ///  
        public void MoveLast() { 
            Position = Count - 1;
        } 

        /// 
        public void MoveNext() {
            ++Position; 
        }
 
        ///  
        public void MovePrevious() {
            --Position; 
        }

        // This method is used to fire ListChanged events when the inner list
        // is not an IBindingList (and therefore cannot fire them itself). 
        //
        private void OnSimpleListChanged(ListChangedType listChangedType, int newIndex) { 
            if (!isBindingList) { 
                OnListChanged(new ListChangedEventArgs(listChangedType, newIndex));
            } 
        }

        /// 
        protected virtual void OnAddingNew(AddingNewEventArgs e) { 
            AddingNewEventHandler eh = (AddingNewEventHandler) Events[EVENT_ADDINGNEW];
            if (eh != null) 
                eh(this, e); 
        }
 
        /// 
        protected virtual void OnBindingComplete(BindingCompleteEventArgs e) {
            BindingCompleteEventHandler eh = (BindingCompleteEventHandler) Events[EVENT_BINDINGCOMPLETE];
            if (eh != null) 
                eh(this, e);
        } 
 
        /// 
        protected virtual void OnCurrentChanged(EventArgs e) { 
            // Unhook change events for old current item (recorded by currentItemHookedForItemChange)
            UnhookItemChangedEventsForOldCurrent();

            // Hook change events for new current item (as indicated now by this.Current) 
            HookItemChangedEventsForNewCurrent();
 
            EventHandler eh = (EventHandler) Events[EVENT_CURRENTCHANGED]; 
            if (eh != null)
                eh(this, e); 
        }

        /// 
        protected virtual void OnCurrentItemChanged(EventArgs e) { 
            EventHandler eh = (EventHandler) Events[EVENT_CURRENTITEMCHANGED];
            if (eh != null) 
                eh(this, e); 
        }
 
        /// 
        protected virtual void OnDataError(BindingManagerDataErrorEventArgs e) {
            BindingManagerDataErrorEventHandler eh = Events[EVENT_DATAERROR] as BindingManagerDataErrorEventHandler;
            if (eh != null) 
                eh(this, e);
        } 
 
        /// 
        protected virtual void OnDataMemberChanged(EventArgs e) { 
            EventHandler eh = Events[EVENT_DATAMEMBERCHANGED] as EventHandler;
            if (eh != null)
                eh(this, e);
        } 

        ///  
        protected virtual void OnDataSourceChanged(EventArgs e) { 
            EventHandler eh = Events[EVENT_DATASOURCECHANGED] as EventHandler;
            if (eh != null) 
                eh(this, e);
        }

        ///  
        protected virtual void OnListChanged(ListChangedEventArgs e) {
            // Sometimes we are required to suppress ListChanged events 
            if (!this.raiseListChangedEvents || this.initializing) { 
                return;
            } 

            ListChangedEventHandler eh = (ListChangedEventHandler)Events[EVENT_LISTCHANGED];
            if (eh != null)
                eh(this, e); 
        }
 
        ///  
        protected virtual void OnPositionChanged(EventArgs e) {
            EventHandler eh = (EventHandler) Events[EVENT_POSITIONCHANGED]; 
            if (eh != null)
                eh(this,e);
        }
 
        //
        // ParentCurrencyManager_CurrentItemChanged() 
        // 
        // When the data member is set, and the data source signals a change of current item,
        // we need to query its new current item for the list specified by the data member. 
        // Or if there is no longer a current item on the data source, we use an empty list.
        // In either case, we only have to change lists, not metadata, since we can assume
        // that the new list has the same item properties as the old list.
        // 
        private void ParentCurrencyManager_CurrentItemChanged(object sender, EventArgs e) {
            if (this.initializing) 
                return; 

            // Commit pending changes in prior list (VSWhidbey #418447) 
            if (parentsCurrentItemChanging) {
                return;
            }
            try { 
                parentsCurrentItemChanging = true;
                // Do what RelatedCurrencyManager does when the parent changes: 
                // 1. PullData from the controls into the back end. 
                // 2. Don't EndEdit the transaction.
                bool success; 
                this.currencyManager.PullData(out success);
            }
            finally {
                parentsCurrentItemChanging = false; 
            }
 
            CurrencyManager cm = (CurrencyManager)sender; 

            // track if the current list changed 
            bool currentItemChanged = true;

            if (!String.IsNullOrEmpty(this.dataMember)) {
                object currentValue = null; 
                IList currentList = null;
 
                if (cm.Count > 0) { 
                    // If parent list has a current item, get the sub-list from the relevant property on that item
                    PropertyDescriptorCollection dsProps = cm.GetItemProperties(); 
                    PropertyDescriptor dmProp = dsProps[this.dataMember];
                    if (dmProp != null) {
                        currentValue = ListBindingHelper.GetList(dmProp.GetValue(cm.Current));
                        currentList = currentValue as IList; 
                    }
                } 
 
                if (currentList != null) {
                    // Yippeeee, the current item gave us a list to bind to! 
                    // [NOTE: Specify applySortAndFilter=TRUE to apply our sort/filter settings to new list]
                    SetList(currentList, false, true);
                }
                else if (currentValue != null) { 
                    // Ok, we didn't get a list, but we did get something, so wrap it in a list
                    // [NOTE: Specify applySortAndFilter=FALSE to stop BindingList from throwing] 
                    SetList(WrapObjectInBindingList(currentValue), false, false); 
                }
                else { 
                    // Nothing to bind to (no current item, or item's property returned null).
                    // Create an empty list, using the previously determined item type.
                    // [NOTE: Specify applySortAndFilter=FALSE to stop BindingList from throwing]
                    SetList(CreateBindingList(this.itemType), false, false); 
                }
 
                // After a change of child lists caused by a change in the current parent item, we 
                // should reset the list position (a la RelatedCurrencyManager). But we have to do
                // this explicitly, because a CurrencyManager normally tries to preserve its position 
                // after a list reset event.

                // Only reset the position if the list really changed or if the list
                // position is incorrect 
                currentItemChanged = ((null == lastCurrentItem) || (cm.Count == 0) || (lastCurrentItem != cm.Current) || (this.Position >= this.Count));
 
                // Save last current item 
                lastCurrentItem = cm.Count > 0 ? cm.Current : null;
 
                if (currentItemChanged) {
                    this.Position = (this.Count > 0 ? 0 : -1);
                }
            } 

            OnCurrentItemChanged(EventArgs.Empty); 
        } 

        // 
        // ParentCurrencyManager_MetaDataChanged()
        //
        // When the data source signals a change of metadata, we need to re-query for the list specified
        // by the data member field. If the data member is no longer valid under the data source's new 
        // metadata, we have no choice but to clear the data member field and just bind directly to the
        // data source itself. 
        // 
        private void ParentCurrencyManager_MetaDataChanged(object sender, EventArgs e) {
            ClearInvalidDataMember(); 
            ResetList();
        }

        // << Some of this code is taken from System.Data.DataTable::ParseSortString method >> 
        private ListSortDescriptionCollection ParseSortString(string sortString) {
            if (String.IsNullOrEmpty(sortString)) { 
                return new ListSortDescriptionCollection(); 
            }
 
            ArrayList sorts = new ArrayList();
            PropertyDescriptorCollection props = this.currencyManager.GetItemProperties();

            string[] split = sortString.Split(new char[] {','}); 
            for (int i = 0; i < split.Length; i++) {
                string current = split[i].Trim(); 
 
                // Handle ASC and DESC
                int length = current.Length; 
                bool ascending = true;
                if (length >= 5 && String.Compare(current, length - 4, " ASC", 0, 4, true, CultureInfo.InvariantCulture) == 0) {
                    current = current.Substring(0, length - 4).Trim();
                } 
                else if (length >= 6 && String.Compare(current, length - 5, " DESC", 0, 5, true, CultureInfo.InvariantCulture) == 0) {
                    ascending = false; 
                    current = current.Substring(0, length - 5).Trim(); 
                }
 
                // Handle brackets
                if (current.StartsWith("[")) {
                    if (current.EndsWith("]")) {
                        current = current.Substring(1, current.Length - 2); 
                    }
                    else { 
                        throw new ArgumentException(SR.GetString(SR.BindingSourceBadSortString)); 
                    }
                } 

                // Find the property
                PropertyDescriptor prop = props.Find(current, true);
                if (prop == null) { 
                    throw new ArgumentException(SR.GetString(SR.BindingSourceSortStringPropertyNotInIBindingList));
                } 
 
                // Add the sort description
                sorts.Add(new ListSortDescription(prop, ascending ? ListSortDirection.Ascending : ListSortDirection.Descending)); 
            }

            ListSortDescription[] result = new ListSortDescription[sorts.Count];
            sorts.CopyTo(result); 
            return new ListSortDescriptionCollection(result);
        } 
 
        /// 
        public void RemoveCurrent() { 
            if (!(this as IBindingList).AllowRemove) {
                throw new InvalidOperationException(SR.GetString(SR.BindingSourceRemoveCurrentNotAllowed));
            }
 
            if (Position < 0 || Position >= Count) {
                throw new InvalidOperationException(SR.GetString(SR.BindingSourceRemoveCurrentNoCurrentItem)); 
            } 

            RemoveAt(Position); 
        }

        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public virtual void ResetAllowNew() {
            this.allowNewIsSet = false; 
            this.allowNewSetValue = true; 
        }
 
        /// 
        public void ResumeBinding() {
            currencyManager.ResumeBinding(); 
        }
 
        ///  
        public void SuspendBinding() {
            currencyManager.SuspendBinding(); 
        }

        //
        // ResetList() 
        //
        // Binds the BindingSource to the list specified by its DataSource and DataMember properties. 
        // 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] // List is cast to IEnumerable twice. Acceptible trade-off versus code clarity (this method contains *critical* logic).
        private void ResetList() { 

            //
            // Don't bind during initialization, since the data source may not have been initialized yet.
            // Instead, set a flag that causes binding to occur on first post-init attempt to access list. 
            //
            if (this.initializing) { 
                needToSetList = true; 
                return;
            } 
            else {
                needToSetList = false;
            }
 
            //
            // Find the list identified by the current DataSource and DataMember properties. 
            // 
            // If the DataSource only specifies a Type, we actually create an
            // instance from that Type and obtain the list from that instance. 
            //
            // Note: The method below will throw an exception if a data member is specified
            // but does not correspond to a valid property on the data source.
            // 
            object dataSourceInstance = (this.dataSource is Type) ? GetListFromType(this.dataSource as Type) : this.dataSource;
            object list = ListBindingHelper.GetList(dataSourceInstance, this.dataMember); 
            this.listExtractedFromEnumerable = false; 

            // 
            // Convert the candidate list into an IList, if necessary...
            //
            if (list is IList) {
                // If its already an IList then we're done! 
            }
            else if (list is IEnumerable) { 
                // If its an enumerable list, extract its contents and put them in a new list 
                list = GetListFromEnumerable(list as IEnumerable);
                this.listExtractedFromEnumerable = true; 
            }
            else if (list != null) {
                // If its some random non-list object, just wrap it in a list
                list = WrapObjectInBindingList(list); 
            }
            else { 
                // Can't get any list from the data source (eg. data member specifies related sub-list but the 
                // data source's list is empty, so there is no current item to get the sub-list from). In this
                // case we simply determine what the list's item type would be, and create empty list with that 
                // same item type. If the item type cannot be determined, we end up with an item type of 'Object'.
                list = CreateBindingList(ListBindingHelper.GetListItemType(this.dataSource, this.dataMember));
            }
 
            //
            // Bind to this list now 
            // 
            SetList(list as IList, true, true);
        } 

        //
        // SetList()
        // 
        // Binds the BindingSource to the specified list, rewiring internal event handlers,
        // firing any appropriate external events, and updating all relevant field members. 
        // 

        private void SetList(IList list, bool metaDataChanged, bool applySortAndFilter) { 
            if (list == null) {
                // The list argument should never be null! We will handle null gracefully
                // at run-time, but we will complain bitterly about this in debug builds!
                Debug.Fail("BindingSource.SetList() was called with illegal  list argument!"); 
                list = CreateBindingList(this.itemType);
            } 
 
            // Unwire stuff from the old list
            UnwireInnerList(); 
            UnhookItemChangedEventsForOldCurrent();

            // Bind to the new list
            this._innerList = list; 

            // Remember whether the new list implements IBindingList 
            this.isBindingList = (list is IBindingList); 

            // 
            // Determine whether the new list converts PropertyChanged events on its items into ListChanged events.
            // If it does, then the BindingSource won't need to hook the PropertyChanged events itself. If the list
            // implements IRaiseItemChangedEvents, we can ask it directly. Otherwise we will assume that any list
            // which impements IBindingList automatically supports this capability. 
            //
            if (list is IRaiseItemChangedEvents) { 
                this.listRaisesItemChangedEvents = (list as IRaiseItemChangedEvents).RaisesItemChangedEvents; 
            }
            else { 
                this.listRaisesItemChangedEvents = this.isBindingList;
            }

            // If list schema may have changed, update list item info now 
            if (metaDataChanged) {
                this.itemType = ListBindingHelper.GetListItemType(List); 
                this.itemShape = ListBindingHelper.GetListItemProperties(List); 
                this.itemConstructor = this.itemType.GetConstructor(BindingFlags.Public |
                                                                    BindingFlags.Instance | 
                                                                    BindingFlags.CreateInstance,
                                                                    null, new Type[0], null);
            }
 
            // Wire stuff up to the new list
            WireInnerList(); 
            HookItemChangedEventsForNewCurrent(); 

            // Fire list reset and/or metadata changed events 
            ResetBindings(metaDataChanged);

            //
            // Apply any custom Sort and Filter values to the new list. 
            //
            // NOTE: The list will throw a NotSupportedException here if it rejects the new sort 
            // and filter settings (either because it doesn't support sorting and filtering, or 
            // because the sort or filter values were invalid).
            // 
            if (applySortAndFilter) {
                if (this.Sort != null) {
                    this.InnerListSort = this.Sort;
                } 
                if (this.Filter != null) {
                    this.InnerListFilter = this.Filter; 
                } 
            }
        } 

        private static IList WrapObjectInBindingList(object obj) {
            IList list = CreateBindingList(obj.GetType());
            list.Add(obj); 
            return list;
        } 
 
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)] 
        internal virtual bool ShouldSerializeAllowNew() {
            return this.allowNewIsSet;
        }
 
        ///////////////////////////////////////////////////////////////////////////////
        // 
        // ItemChanged event support 
        //
        /////////////////////////////////////////////////////////////////////////////// 

        // Hooks property changed events for the NEW current item, if nececssary
        private void HookItemChangedEventsForNewCurrent() {
            Debug.Assert(this.currentItemHookedForItemChange == null, "BindingSource trying to hook new current item before unhooking old current item!"); 

            if (!this.listRaisesItemChangedEvents) { 
                if (this.Position >= 0 && this.Position <= this.Count - 1) { 
                    this.currentItemHookedForItemChange = this.Current;
                    WirePropertyChangedEvents(this.currentItemHookedForItemChange); 
                }
                else {
                    this.currentItemHookedForItemChange = null;
                } 
            }
        } 
 
        // Unhooks property changed events for the OLD current item, if necessary
        private void UnhookItemChangedEventsForOldCurrent() { 
            if (!this.listRaisesItemChangedEvents) {
                UnwirePropertyChangedEvents(this.currentItemHookedForItemChange);
                this.currentItemHookedForItemChange = null;
            } 
        }
 
        /////////////////////////////////////////////////////////////////////////////// 
        //
        // Event wiring and unwiring methods 
        //
        ///////////////////////////////////////////////////////////////////////////////

        private void WireCurrencyManager(CurrencyManager cm) { 
            if (cm != null) {
                cm.PositionChanged    += new EventHandler(CurrencyManager_PositionChanged); 
                cm.CurrentChanged     += new EventHandler(CurrencyManager_CurrentChanged); 
                cm.CurrentItemChanged += new EventHandler(CurrencyManager_CurrentItemChanged);
                cm.BindingComplete    += new BindingCompleteEventHandler(CurrencyManager_BindingComplete); 
                cm.DataError          += new BindingManagerDataErrorEventHandler(CurrencyManager_DataError);
            }
        }
 
        private void UnwireCurrencyManager(CurrencyManager cm) {
            if (cm != null) { 
                cm.PositionChanged    -= new EventHandler(CurrencyManager_PositionChanged); 
                cm.CurrentChanged     -= new EventHandler(CurrencyManager_CurrentChanged);
                cm.CurrentItemChanged -= new EventHandler(CurrencyManager_CurrentItemChanged); 
                cm.BindingComplete    -= new BindingCompleteEventHandler(CurrencyManager_BindingComplete);
                cm.DataError          -= new BindingManagerDataErrorEventHandler(CurrencyManager_DataError);
            }
        } 

        private void WireDataSource() { 
            if (dataSource is ICurrencyManagerProvider) { 
                CurrencyManager cm  = (dataSource as ICurrencyManagerProvider).CurrencyManager;
                cm.CurrentItemChanged += new EventHandler(ParentCurrencyManager_CurrentItemChanged); 
                cm.MetaDataChanged    += new EventHandler(ParentCurrencyManager_MetaDataChanged);
            }
        }
 
        private void UnwireDataSource() {
            if (dataSource is ICurrencyManagerProvider) { 
                CurrencyManager cm  = (dataSource as ICurrencyManagerProvider).CurrencyManager; 
                cm.CurrentItemChanged -= new EventHandler(ParentCurrencyManager_CurrentItemChanged);
                cm.MetaDataChanged    -= new EventHandler(ParentCurrencyManager_MetaDataChanged); 
            }
        }

        private void WireInnerList() { 
            if (_innerList is IBindingList) {
                IBindingList list = _innerList as IBindingList; 
                list.ListChanged += new ListChangedEventHandler(InnerList_ListChanged); 
            }
        } 

        private void UnwireInnerList() {
            if (_innerList is IBindingList) {
                IBindingList list = _innerList as IBindingList; 
                list.ListChanged -= new ListChangedEventHandler(InnerList_ListChanged);
            } 
        } 

        private void WirePropertyChangedEvents(object item) { 
            if (item != null && this.itemShape != null) {
                for (int j = 0; j < this.itemShape.Count; j++) {
                    this.itemShape[j].AddValueChanged(item, listItemPropertyChangedHandler);
                } 
            }
        } 
 
        private void UnwirePropertyChangedEvents(object item) {
            if (item != null && this.itemShape != null) { 
                for (int j = 0; j < this.itemShape.Count; j++) {
                    this.itemShape[j].RemoveValueChanged(item, listItemPropertyChangedHandler);
                }
            } 
        }
        #endregion Methods 
 
        #region ISupportInitialize/ISupportInitializeNotification
        /////////////////////////////////////////////////////////////////////////////// 
        //
        // ISupportInitialize and ISupportInitializeNotification interfaces
        //
        /////////////////////////////////////////////////////////////////////////////// 

        // Begin bulk member initialization - deferring calculation of inner list until EndInit is reached 
        // 
        void ISupportInitialize.BeginInit() {
            initializing = true; 
        }

        // End bulk member initialization - updating the inner list and notifying any dependents of our completion
        // 
        private void EndInitCore() {
            initializing = false; 
            EnsureInnerList(); 
            OnInitialized();
        } 

        // Check to see if DataSource has completed its initialization, before ending our initialization.
        // If DataSource is still initializing, hook its Initialized event and wait for it to signal completion.
        // If DataSource is already initialized, just go ahead and complete our initialization now. 
        //
        void ISupportInitialize.EndInit() { 
            ISupportInitializeNotification dsInit = (this.DataSource as ISupportInitializeNotification); 

            if (dsInit != null && !dsInit.IsInitialized) { 
                dsInit.Initialized += new EventHandler(DataSource_Initialized);
            }
            else {
                EndInitCore(); 
            }
        } 
 
        // Respond to late completion of the DataSource's initialization, by completing our own initialization.
        // This situation can arise if the call to the DataSource's EndInit() method comes after the call to the 
        // BindingSource's EndInit() method (since code-generated ordering of these calls is non-deterministic).
        //
        private void DataSource_Initialized(object sender, EventArgs e) {
            ISupportInitializeNotification dsInit = (this.DataSource as ISupportInitializeNotification); 

            Debug.Assert(dsInit != null, "BindingSource: ISupportInitializeNotification.Initialized event received, but current DataSource does not support ISupportInitializeNotification!"); 
            Debug.Assert(dsInit.IsInitialized, "BindingSource: DataSource sent ISupportInitializeNotification.Initialized event but before it had finished initializing."); 

            if (dsInit != null) { 
                dsInit.Initialized -= new EventHandler(DataSource_Initialized);
            }

            EndInitCore(); 
        }
 
        // Report to any dependents whether we are still in bulk member initialization 
        //
        bool ISupportInitializeNotification.IsInitialized { 
            get {
                return !initializing;
            }
        } 

        // Event used to signal to our dependents that we have completed bulk member initialization and updated our inner list 
        // 
        event EventHandler ISupportInitializeNotification.Initialized {
            add { 
                Events.AddHandler(EVENT_INITIALIZED, value);
            }
            remove {
                Events.RemoveHandler(EVENT_INITIALIZED, value); 
            }
        } 
 
        // Method used to raise the Initialized event above
        // 
        private void OnInitialized() {
            EventHandler eh = (EventHandler) Events[EVENT_INITIALIZED];
            if (eh != null)
                eh(this, EventArgs.Empty); 
        }
        #endregion ISupportInitialize/ISupportInitializeNotification 
 
        #region IEnumerable
        /////////////////////////////////////////////////////////////////////////////// 
        //
        // IEnumerable interface
        //
        /////////////////////////////////////////////////////////////////////////////// 

        public virtual IEnumerator GetEnumerator() { 
            return List.GetEnumerator(); 
        }
        #endregion 

        #region ICollection
        ///////////////////////////////////////////////////////////////////////////////
        // 
        // ICollection interface
        // 
        /////////////////////////////////////////////////////////////////////////////// 

        public virtual void CopyTo(Array arr, int index) { 
            List.CopyTo(arr, index);
        }

        [Browsable(false)] 
        public virtual int Count {
            get { 
                try 
                {
                    if (disposedOrFinalized) 
                    {
                        return 0;
                    }
                    if (recursionDetectionFlag) 
                    {
                        throw new InvalidOperationException(SR.GetString(SR.BindingSourceRecursionDetected)); 
                    } 
                    recursionDetectionFlag = true;
 
                    return List.Count;
                }
                finally
                { 
                    recursionDetectionFlag = false;
                } 
            } 
        }
 
        [Browsable(false)]
        public virtual bool IsSynchronized
        {
            get { 
                return List.IsSynchronized;
            } 
        } 

        [Browsable(false)] 
        public virtual object SyncRoot {
            get {
                return List.SyncRoot;
            } 
        }
 
        #endregion ICollection 

        #region IList 
        ///////////////////////////////////////////////////////////////////////////////
        //
        // IList interface
        // 
        ///////////////////////////////////////////////////////////////////////////////
 
        /// 
        public virtual object AddNew() { 
            // Throw if adding new items has been disabled
            if (!AllowNewInternal(false)) {
                throw new InvalidOperationException(SR.GetString(SR.BindingSourceBindingListWrapperAddToReadOnlyList));
            } 

            if (!AllowNewInternal(true)) { 
                throw new InvalidOperationException(SR.GetString( 
                    SR.BindingSourceBindingListWrapperNeedToSetAllowNew,
                    itemType == null ? "(null)" : itemType.FullName 
                    ));
            }

            // Remember this since EndEdit() below will clear it 
            int saveAddNew = this.addNewPos;
 
            // Commit any uncomitted list changes now 
            EndEdit();
 
            // We just committed a new item; mimic DataView and fire an ItemAdded event for it here
            if (saveAddNew != -1) {
                OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, saveAddNew));
            } 

            // Raise the AddingNew event in case listeners want to supply the new item for us 
            AddingNewEventArgs addingNew = new AddingNewEventArgs(); 
            int oldCount = List.Count;
            OnAddingNew(addingNew); 
            object addNewItem = addingNew.NewObject;

            //
            // If no item came back from AddingNew event, we must create the new item ourselves... 
            //
            if (addNewItem == null) { 
                // If the inner list is an IBindingList, let it create and add the new item for us. 
                // Then make the new item the current item (...assuming, as CurrencyManager does,
                // that the new item was added at the *bottom* of the list). 
                if (isBindingList) {
                    addNewItem = (List as IBindingList).AddNew();
                    this.Position = this.Count - 1;
                    return addNewItem; 
                }
 
                // Throw if we don't know how to create items of the current item type 
                if (this.itemConstructor == null) {
                    throw new InvalidOperationException(SR.GetString( 
                        SR.BindingSourceBindingListWrapperNeedAParameterlessConstructor,
                        itemType == null ? "(null)" : itemType.FullName
                        ));
                } 

                // Create new item using default ctor for current item type 
                addNewItem = this.itemConstructor.Invoke(null); 
            }
 
            if (List.Count > oldCount) {
                // If event handler has already added item to list, then simply record the item's position
                this.addNewPos = this.Position;
            } 
            else {
                // If event handler has not yet added item to list, then add it 
                // ourselves, make it the current item, and record its position. 
                this.addNewPos = this.Add(addNewItem);
                this.Position = this.addNewPos; 
            }

            return addNewItem;
        } 

        [Browsable(false)] 
        public virtual bool AllowEdit { 
            get {
                if (isBindingList) { 
                    return ((IBindingList) List).AllowEdit;
                }
                else {
                    return !List.IsReadOnly; 
                }
            } 
        } 

        [ 
        SRCategory(SR.CatBehavior),
        SRDescription(SR.BindingSourceAllowNewDescr),
        ]
        ///  
        public virtual bool AllowNew {
            get { 
                //we check to ensure we have a valid default constructor (if we get that far). 
                return AllowNewInternal(true);
            } 

            set {
                // If value was previously set and isn't changing now, do nothing
                if (this.allowNewIsSet && value == this.allowNewSetValue) { 
                    return;
                } 
 
                // Don't let user set value to true if inner list can never support adding of items
                // do NOT check for a default constructor because someone will set AllowNew=True 
                // when they have overridden OnAddingNew (which we cannot detect).
                if (value == true && !isBindingList && !IsListWriteable(false)) {
                    throw new InvalidOperationException(SR.GetString(SR.NoAllowNewOnReadOnlyList));
                } 

                // Record new value, which will now override inner list's value 
                this.allowNewIsSet = true; 
                this.allowNewSetValue = value;
 
                // Mimic the DataView class and fire a list reset event now
                OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
            }
        } 

        [Browsable(false)] 
        public virtual bool AllowRemove { 
            get {
                if (isBindingList) { 
                    return ((IBindingList) List).AllowRemove;
                }
                else {
                    return !List.IsReadOnly && !List.IsFixedSize; 
                }
            } 
        } 

        [Browsable(false)] 
        public virtual bool SupportsChangeNotification {
            get {
                return true;
            } 
        }
 
        [Browsable(false)] 
        public virtual bool SupportsSearching {
            get { 
                if (isBindingList) {
                    return ((IBindingList) List).SupportsSearching;
                }
                else { 
                    return false;
                } 
            } 
        }
 
        [Browsable(false)]
        public virtual bool SupportsSorting {
            get {
                if (isBindingList) { 
                    return ((IBindingList) List).SupportsSorting;
                } 
                else { 
                    return false;
                } 
            }
        }

        [Browsable(false)] 
        public virtual bool IsSorted {
            get { 
                if (isBindingList) { 
                    return ((IBindingList) List).IsSorted;
                } 
                else {
                    return false;
                }
            } 
        }
 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public virtual PropertyDescriptor SortProperty {
            get { 
                if (isBindingList) {
                    return ((IBindingList) List).SortProperty;
                }
                else { 
                    return null;
                } 
            } 
        }
 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public virtual ListSortDirection SortDirection {
            get {
                if (isBindingList) { 
                    return ((IBindingList) List).SortDirection;
                } 
                else { 
                    return ListSortDirection.Ascending;
                } 
            }
        }

        void IBindingList.AddIndex(PropertyDescriptor property) { 
            if (isBindingList) {
                ((IBindingList) List).AddIndex(property); 
            } 
            else {
                throw new NotSupportedException(SR.GetString(SR.OperationRequiresIBindingList)); 
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never)] 
        public virtual void ApplySort(PropertyDescriptor property, ListSortDirection sort) {
            if (isBindingList) { 
                ((IBindingList) List).ApplySort(property, sort); 
            }
            else { 
                throw new NotSupportedException(SR.GetString(SR.OperationRequiresIBindingList));
            }
        }
 
        public virtual int Find(PropertyDescriptor prop, object key) {
            if (isBindingList) { 
                return ((IBindingList) List).Find(prop, key); 
            }
            else { 
                throw new NotSupportedException(SR.GetString(SR.OperationRequiresIBindingList));
            }
        }
 
        void IBindingList.RemoveIndex(PropertyDescriptor prop) {
            if (isBindingList) { 
                ((IBindingList) List).RemoveIndex(prop); 
            }
            else { 
                throw new NotSupportedException(SR.GetString(SR.OperationRequiresIBindingList));
            }
        }
 
        public virtual void RemoveSort() {
            this.sort = null; 
 
            if (isBindingList) {
                ((IBindingList) List).RemoveSort(); 
            }
        }
        #endregion IBindingList
 
        #region IBindingListView
        /////////////////////////////////////////////////////////////////////////////// 
        // 
        // IBindingListView interface
        // 
        ///////////////////////////////////////////////////////////////////////////////

        [EditorBrowsable(EditorBrowsableState.Never)]
        public virtual void ApplySort(ListSortDescriptionCollection sorts) { 
            IBindingListView iblw = List as IBindingListView;
            if (iblw != null) { 
                iblw.ApplySort(sorts); 
            }
            else { 
                throw new NotSupportedException(SR.GetString(SR.OperationRequiresIBindingListView));
            }
        }
 

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public virtual ListSortDescriptionCollection SortDescriptions { 
            get {
                IBindingListView iblw = List as IBindingListView; 
                if (iblw != null) {
                    return iblw.SortDescriptions;
                } else {
                    return null; 
                }
            } 
        } 

        [ 
        SRCategory(SR.CatData),
        DefaultValue(null),
        SRDescription(SR.BindingSourceFilterDescr)
        ] 
        ///  relatedBindingSources; 

        // Support for user-overriding of the AllowNew property
        private bool allowNewIsSet       = false;
        private bool allowNewSetValue    = true; 

        // Support for property change event hooking on list items 
        private object currentItemHookedForItemChange = null; 
        private object lastCurrentItem = null;
        private EventHandler listItemPropertyChangedHandler; 

        // State data
        private int  addNewPos = -1;
        private bool initializing = false; 
        private bool needToSetList = false;
        private bool recursionDetectionFlag = false; 
        private bool innerListChanging = false; 
        private bool endingEdit = false;
 

        ///////////////////////////////////////////////////////////////////////////////
        //
        // Constructors 
        //
        /////////////////////////////////////////////////////////////////////////////// 
 
        /// (); 
            } 

            // Look for an existing binding source that uses this data member, and return that 
            foreach (string key in this.relatedBindingSources.Keys) {
                if (String.Equals(key, dataMember, StringComparison.OrdinalIgnoreCase)) {
                    return this.relatedBindingSources[key];
                } 
            }
 
            // Otherwise create the related binding source, cache it, and return it 
            BindingSource bs = new BindingSource(this, dataMember);
            this.relatedBindingSources[dataMember] = bs; 
            return bs;
        }

        ///  
        [Browsable(false)]
        public object Current { 
            get { 
                return currencyManager.Count > 0 ? currencyManager.Current : null;
            } 
        }

        [
        SRCategory(SR.CatData), 
        DefaultValue(""),
        RefreshProperties(RefreshProperties.Repaint), 
        Editor("System.Windows.Forms.Design.DataMemberListEditor, " + AssemblyRef.SystemDesign, typeof(System.Drawing.Design.UITypeEditor)), 
        SRDescription(SR.BindingSourceDataMemberDescr)
        ] 
        ///  
        [Browsable(false)] 
        public bool IsBindingSuspended {
            get { 
                return currencyManager.IsBindingSuspended;
            }
        }
 
        [Browsable(false)]
        /// 
        public string Sort { 
            get { 
                return this.sort;
            } 
            set {
                this.sort = value;
                InnerListSort = value;
            } 
        }
 
        #region Events 
        ///////////////////////////////////////////////////////////////////////////////
        // 
        // Events
        //
        ///////////////////////////////////////////////////////////////////////////////
 
        [
        SRCategory(SR.CatData), 
        SRDescription(SR.BindingSourceAddingNewEventHandlerDescr) 
        ]
        ///  
        public event AddingNewEventHandler AddingNew {
            add {
                Events.AddHandler(EVENT_ADDINGNEW, value);
            } 
            remove {
                Events.RemoveHandler(EVENT_ADDINGNEW, value); 
            } 
        }
 
        /// 
        [
        SRCategory(SR.CatData),
        SRDescription(SR.BindingSourceBindingCompleteEventHandlerDescr) 
        ]
        public event BindingCompleteEventHandler BindingComplete { 
            add { 
                Events.AddHandler(EVENT_BINDINGCOMPLETE, value);
            } 
            remove {
                Events.RemoveHandler(EVENT_BINDINGCOMPLETE, value);
            }
        } 

        [ 
        SRCategory(SR.CatData), 
        SRDescription(SR.BindingSourceDataErrorEventHandlerDescr)
        ] 
        /// 
        public event BindingManagerDataErrorEventHandler DataError {
            add {
                Events.AddHandler(EVENT_DATAERROR, value); 
            }
            remove { 
                Events.RemoveHandler(EVENT_DATAERROR, value); 
            }
        } 

        [
        SRCategory(SR.CatData),
        SRDescription(SR.BindingSourceDataSourceChangedEventHandlerDescr) 
        ]
        ///  
        public event EventHandler DataSourceChanged { 
            add {
                Events.AddHandler(EVENT_DATASOURCECHANGED, value); 
            }
            remove {
                Events.RemoveHandler(EVENT_DATASOURCECHANGED, value);
            } 
        }
 
        [ 
        SRCategory(SR.CatData),
        SRDescription(SR.BindingSourceDataMemberChangedEventHandlerDescr) 
        ]
        /// 
        public event EventHandler DataMemberChanged {
            add { 
                Events.AddHandler(EVENT_DATAMEMBERCHANGED, value);
            } 
            remove { 
                Events.RemoveHandler(EVENT_DATAMEMBERCHANGED, value);
            } 
        }

        [
        SRCategory(SR.CatData), 
        SRDescription(SR.BindingSourceCurrentChangedEventHandlerDescr)
        ] 
        ///  
        public event EventHandler CurrentChanged {
            add { 
                Events.AddHandler(EVENT_CURRENTCHANGED, value);
            }
            remove {
                Events.RemoveHandler(EVENT_CURRENTCHANGED, value); 
            }
        } 
 
        [
        SRCategory(SR.CatData), 
        SRDescription(SR.BindingSourceCurrentItemChangedEventHandlerDescr)
        ]
        /// 
        public event EventHandler CurrentItemChanged { 
            add {
                Events.AddHandler(EVENT_CURRENTITEMCHANGED, value); 
            } 
            remove {
                Events.RemoveHandler(EVENT_CURRENTITEMCHANGED, value); 
            }
        }

        [ 
        SRCategory(SR.CatData),
        SRDescription(SR.BindingSourceListChangedEventHandlerDescr) 
        ] 
        /// 
        public event ListChangedEventHandler ListChanged { 
            add {
                Events.AddHandler(EVENT_LISTCHANGED, value);
            }
            remove { 
                Events.RemoveHandler(EVENT_LISTCHANGED, value);
            } 
        } 

        [ 
        SRCategory(SR.CatData),
        SRDescription(SR.BindingSourcePositionChangedEventHandlerDescr)
        ]
        ///  
        public event EventHandler PositionChanged {
            add { 
                Events.AddHandler(EVENT_POSITIONCHANGED, value); 
            }
            remove { 
                Events.RemoveHandler(EVENT_POSITIONCHANGED, value);
            }
        }
        #endregion Events 

        #region Methods 
        /////////////////////////////////////////////////////////////////////////////// 
        //
        // Methods 
        //
        ///////////////////////////////////////////////////////////////////////////////

        /* CUT: 

        // 
        // AutoSetDataMember() 
        //
        // Used when data source changes. If data member is not set, and the data source 
        // is a list of lists, arbitrarily point the data member at one of these lists.
        //
        private void AutoSetDataMember() {
            // Data member already assigned! 
            if (!String.IsNullOrEmpty(this.dataMember)) {
                return; 
            } 

            // Get the list of lists 
            IListSource listSource = this.dataSource as IListSource;

            // Not a list of lists!
            if (listSource == null || !listSource.ContainsListCollection) { 
                return;
            } 
 
            // Get properties of data source
            PropertyDescriptorCollection props = ListBindingHelper.GetListItemProperties(listSource); 

            // Walk properties of data source, looking for one that returns IList (but ignoring ones that return Array)
            for (int i = 0; i < props.Count; ++i) {
                PropertyDescriptor prop = props[i]; 

                if (typeof(IList).IsAssignableFrom(prop.PropertyType) && !typeof(Array).IsAssignableFrom(prop.PropertyType)) { 
                    // Bingo - got one! 
                    this.dataMember = prop.Name;
                    OnDataMemberChanged(EventArgs.Empty); 
                    break;
                }
            }
        } 

        */ 
 
        private static string BuildSortString(ListSortDescriptionCollection sortsColln) {
                if (sortsColln == null) { 
                    return String.Empty;
                }

                StringBuilder sb = new StringBuilder(sortsColln.Count); 

                for (int i = 0; i < sortsColln.Count; ++i) { 
                    sb.Append(sortsColln[i].PropertyDescriptor.Name + 
                              ((sortsColln[i].SortDirection == ListSortDirection.Ascending) ? " ASC" : " DESC") +
                              ((i < sortsColln.Count - 1) ? "," : String.Empty)); 
                }

                return sb.ToString();
        } 

        ///  
        public void CancelEdit() { 
            currencyManager.CancelCurrentEdit();
        } 

        // Walks the BindingSource::DataSource chain until
        // 1. there is a break in the chain ( BindingSource::DataSource is not a BindingSource ), or
        // 2. detects a cycle in the chain. 
        // If a cycle is detected we throw the BindingSourceRecursionDetected exception
        private void ThrowIfBindingSourceRecursionDetected(object newDataSource) { 
            BindingSource bindingSource = newDataSource as BindingSource; 

            while (bindingSource != null) { 
                if (bindingSource == this) {
                    throw new InvalidOperationException(SR.GetString(SR.BindingSourceRecursionDetected));
                }
                bindingSource = bindingSource.DataSource as BindingSource; 
            }
        } 
 
        private void ClearInvalidDataMember() {
            if (!IsDataMemberValid()) { 
                this.dataMember = "";
                OnDataMemberChanged(EventArgs.Empty);
            }
        } 

        // Creates an instance of BindingList where T is only known at run time, not compile time 
        private static IList CreateBindingList(Type type) { 
            Type genericType = typeof(BindingList<>);
            Type bindingType = genericType.MakeGenericType(new Type[] { type }); 

            return (IList) SecurityUtils.SecureCreateInstance(bindingType);
        }
 
        // Create an object of the given type. Throw an exception if this fails.
        private static object CreateInstanceOfType(Type type) { 
            object instancedObject = null; 
            Exception instanceException = null;
 
            try {
                instancedObject = SecurityUtils.SecureCreateInstance(type);
            }
            catch (TargetInvocationException ex) { 
                instanceException = ex; // Default ctor threw an exception
            } 
            catch (MethodAccessException ex) { 
                instanceException = ex; // Default ctor was not public
            } 
            catch (MissingMethodException ex) {
                instanceException = ex; // No default ctor defined
            }
 
            if (instanceException != null) {
                throw new NotSupportedException(SR.GetString(SR.BindingSourceInstanceError), instanceException); 
            } 

            return instancedObject; 
        }

        private void CurrencyManager_PositionChanged(object sender, EventArgs e) {
            Debug.Assert(sender == this.currencyManager, "only receive notifications from the currency manager"); 
            OnPositionChanged(e);
        } 
 
        private void CurrencyManager_CurrentChanged(object sender, EventArgs e) {
            OnCurrentChanged(EventArgs.Empty); 
        }

        private void CurrencyManager_CurrentItemChanged(object sender, EventArgs e) {
            OnCurrentItemChanged(EventArgs.Empty); 
        }
 
        private void CurrencyManager_BindingComplete(object sender, BindingCompleteEventArgs e) { 
            OnBindingComplete(e);
        } 

        private void CurrencyManager_DataError(object sender, BindingManagerDataErrorEventArgs e) {
            OnDataError(e);
        } 

        ///  
        ///     Unhook BindingSource from its data source, since the data source could be some 
        ///     global object who's lifetime exceeds the lifetime of the parent form. Otherwise
        ///     the BindingSource (and any components bound through it) will end up in limbo, 
        ///     still processing list change events, etc. And when unhooking from the data source,
        ///     take care not to trigger any events that could confuse compoents bound to us.
        /// 
        protected override void Dispose(bool disposing) { 
            if (disposing) {
                UnwireDataSource(); 
                UnwireInnerList(); 
                UnhookItemChangedEventsForOldCurrent();
                UnwireCurrencyManager(this.currencyManager); 
                this.dataSource = null;
                this.sort = null;
                this.dataMember = null;
                this._innerList = null; 
                this.isBindingList = false;
                this.needToSetList = true; 
                this.raiseListChangedEvents = false; 
            }
            disposedOrFinalized = true; 
            base.Dispose(disposing);
        }

        ///  
        public void EndEdit() {
            if (endingEdit) { 
                return; 
            }
            try { 
                endingEdit = true;
                currencyManager.EndCurrentEdit();
            }
            finally { 
                endingEdit = false;
            } 
        } 

        // 
        // EnsureInnerList()
        //
        // Ensures that the inner list has been set up. Handles the case of ResetList() being called during
        // initialization, which sets a flag to defer ResetList() work until after initialization is complete. 
        //
        private void EnsureInnerList() { 
            if (!this.initializing && needToSetList) { 
                needToSetList = false;
                ResetList(); 
            }
        }

        // 
        // Find()
        // 
        // Overload of IBindingList.Find that takes a string instead of a property descriptor (for convenience). 
        //
        public int Find(String propertyName, object key) { 
            PropertyDescriptor pd = (itemShape == null) ? null : itemShape.Find(propertyName, true);

            if (pd == null) {
                throw new System.ArgumentException(SR.GetString(SR.DataSourceDataMemberPropNotFound, propertyName)); 
            }
 
            return (this as IBindingList).Find(pd, key); 
        }
 
        //
        // GetListFromType()
        //
        // Given a type, create a list based on that type. If the type represents a list type, 
        // we create an instance of that type (or throw if we cannot instance that type).
        // Otherwise we assume the type represents the item type, in which case we create 
        // a typed BindingList of that item type. 
        //
 
        private static IList GetListFromType(Type type) {
            IList list = null;

            if (typeof(ITypedList).IsAssignableFrom(type) && typeof(IList).IsAssignableFrom(type)) { 
                list = CreateInstanceOfType(type) as IList;
            } 
            else if (typeof(IListSource).IsAssignableFrom(type)) { 
                list = (CreateInstanceOfType(type) as IListSource).GetList();
            } 
            else {
                list = CreateBindingList(ListBindingHelper.GetListItemType(type));
            }
 
            return list;
        } 
 
        //
        // GetListFromEnumerable() 
        //
        // Creates a list based on an enumerable object. We rip through the enumerable,
        // extract all its items, and stuff these items into a typed BindingList, using
        // the type of the first item to determine the type of the list. 
        //
        private static IList GetListFromEnumerable(IEnumerable enumerable) { 
            IList list = null; 

            foreach (object item in enumerable) { 
                if (list == null) {
                    list = CreateBindingList(item.GetType());
                }
 
                list.Add(item);
            } 
 
            return list;
        } 

        //
        // IsDataMemberValid()
        // 
        // Used when we change data sources or when the properties of the current data source change.
        // Decides whether this would be a good time to blow away the data member field, since it 
        // might not refer to a valid data source property any more. 
        //
        private bool IsDataMemberValid() { 
            // Don't mess with things during initialization because the data
            // member property can get set before the data source property.
            if (this.initializing) {
                return true; 
            }
 
            // If data member has not been specified, leave the data member property alone 
            if (String.IsNullOrEmpty(this.dataMember)) {
                return true; 
            }

            // See if data member corresponds to a valid property on the specified data source
            PropertyDescriptorCollection dsProps = ListBindingHelper.GetListItemProperties(this.dataSource); 
            PropertyDescriptor dmProp = dsProps[this.dataMember];
            if (dmProp != null) { 
                return true; 
            }
 
            return false;
        }

        private void InnerList_ListChanged(object sender, ListChangedEventArgs e) { 
            // Set recursive flag - see VSWhidbey 455276
            // Basically, we can have computed columns that cause our parent 
            // to change when our list changes.  This can cause recursion because we update 
            // when our parent updates which then causes our parent to update which
            // then causes us to update which then causes our parent to update which 
            // then causes us to update which then causes our parent to update...
            if (!this.innerListChanging) {
                try {
                    this.innerListChanging = true; 
                    OnListChanged(e);
                } 
                finally { 
                    this.innerListChanging = false;
                } 
            }
        }

        private void ListItem_PropertyChanged(object sender, EventArgs e) { 
            int index;
 
            // Performance: If the item that changed is the current item, we can avoid a potentially expensive call to IndexOf() 
            if (sender == currentItemHookedForItemChange) {
                index = this.Position; 
                Debug.Assert(index >= 0, "BindingSource.ListItem_PropertyChanged - no current item.");
                Debug.Assert(index == ((IList) this).IndexOf(sender), "BindingSource.ListItem_PropertyChanged - unexpected current item.");
            }
            else { 
                index = ((IList) this).IndexOf(sender);
            } 
            OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, index)); 
        }
 
        /// 
        public void MoveFirst() {
            Position = 0;
        } 

        ///  
        public void MoveLast() { 
            Position = Count - 1;
        } 

        /// 
        public void MoveNext() {
            ++Position; 
        }
 
        ///  
        public void MovePrevious() {
            --Position; 
        }

        // This method is used to fire ListChanged events when the inner list
        // is not an IBindingList (and therefore cannot fire them itself). 
        //
        private void OnSimpleListChanged(ListChangedType listChangedType, int newIndex) { 
            if (!isBindingList) { 
                OnListChanged(new ListChangedEventArgs(listChangedType, newIndex));
            } 
        }

        /// 
        protected virtual void OnAddingNew(AddingNewEventArgs e) { 
            AddingNewEventHandler eh = (AddingNewEventHandler) Events[EVENT_ADDINGNEW];
            if (eh != null) 
                eh(this, e); 
        }
 
        /// 
        protected virtual void OnBindingComplete(BindingCompleteEventArgs e) {
            BindingCompleteEventHandler eh = (BindingCompleteEventHandler) Events[EVENT_BINDINGCOMPLETE];
            if (eh != null) 
                eh(this, e);
        } 
 
        /// 
        protected virtual void OnCurrentChanged(EventArgs e) { 
            // Unhook change events for old current item (recorded by currentItemHookedForItemChange)
            UnhookItemChangedEventsForOldCurrent();

            // Hook change events for new current item (as indicated now by this.Current) 
            HookItemChangedEventsForNewCurrent();
 
            EventHandler eh = (EventHandler) Events[EVENT_CURRENTCHANGED]; 
            if (eh != null)
                eh(this, e); 
        }

        /// 
        protected virtual void OnCurrentItemChanged(EventArgs e) { 
            EventHandler eh = (EventHandler) Events[EVENT_CURRENTITEMCHANGED];
            if (eh != null) 
                eh(this, e); 
        }
 
        /// 
        protected virtual void OnDataError(BindingManagerDataErrorEventArgs e) {
            BindingManagerDataErrorEventHandler eh = Events[EVENT_DATAERROR] as BindingManagerDataErrorEventHandler;
            if (eh != null) 
                eh(this, e);
        } 
 
        /// 
        protected virtual void OnDataMemberChanged(EventArgs e) { 
            EventHandler eh = Events[EVENT_DATAMEMBERCHANGED] as EventHandler;
            if (eh != null)
                eh(this, e);
        } 

        ///  
        protected virtual void OnDataSourceChanged(EventArgs e) { 
            EventHandler eh = Events[EVENT_DATASOURCECHANGED] as EventHandler;
            if (eh != null) 
                eh(this, e);
        }

        ///  
        protected virtual void OnListChanged(ListChangedEventArgs e) {
            // Sometimes we are required to suppress ListChanged events 
            if (!this.raiseListChangedEvents || this.initializing) { 
                return;
            } 

            ListChangedEventHandler eh = (ListChangedEventHandler)Events[EVENT_LISTCHANGED];
            if (eh != null)
                eh(this, e); 
        }
 
        ///  
        protected virtual void OnPositionChanged(EventArgs e) {
            EventHandler eh = (EventHandler) Events[EVENT_POSITIONCHANGED]; 
            if (eh != null)
                eh(this,e);
        }
 
        //
        // ParentCurrencyManager_CurrentItemChanged() 
        // 
        // When the data member is set, and the data source signals a change of current item,
        // we need to query its new current item for the list specified by the data member. 
        // Or if there is no longer a current item on the data source, we use an empty list.
        // In either case, we only have to change lists, not metadata, since we can assume
        // that the new list has the same item properties as the old list.
        // 
        private void ParentCurrencyManager_CurrentItemChanged(object sender, EventArgs e) {
            if (this.initializing) 
                return; 

            // Commit pending changes in prior list (VSWhidbey #418447) 
            if (parentsCurrentItemChanging) {
                return;
            }
            try { 
                parentsCurrentItemChanging = true;
                // Do what RelatedCurrencyManager does when the parent changes: 
                // 1. PullData from the controls into the back end. 
                // 2. Don't EndEdit the transaction.
                bool success; 
                this.currencyManager.PullData(out success);
            }
            finally {
                parentsCurrentItemChanging = false; 
            }
 
            CurrencyManager cm = (CurrencyManager)sender; 

            // track if the current list changed 
            bool currentItemChanged = true;

            if (!String.IsNullOrEmpty(this.dataMember)) {
                object currentValue = null; 
                IList currentList = null;
 
                if (cm.Count > 0) { 
                    // If parent list has a current item, get the sub-list from the relevant property on that item
                    PropertyDescriptorCollection dsProps = cm.GetItemProperties(); 
                    PropertyDescriptor dmProp = dsProps[this.dataMember];
                    if (dmProp != null) {
                        currentValue = ListBindingHelper.GetList(dmProp.GetValue(cm.Current));
                        currentList = currentValue as IList; 
                    }
                } 
 
                if (currentList != null) {
                    // Yippeeee, the current item gave us a list to bind to! 
                    // [NOTE: Specify applySortAndFilter=TRUE to apply our sort/filter settings to new list]
                    SetList(currentList, false, true);
                }
                else if (currentValue != null) { 
                    // Ok, we didn't get a list, but we did get something, so wrap it in a list
                    // [NOTE: Specify applySortAndFilter=FALSE to stop BindingList from throwing] 
                    SetList(WrapObjectInBindingList(currentValue), false, false); 
                }
                else { 
                    // Nothing to bind to (no current item, or item's property returned null).
                    // Create an empty list, using the previously determined item type.
                    // [NOTE: Specify applySortAndFilter=FALSE to stop BindingList from throwing]
                    SetList(CreateBindingList(this.itemType), false, false); 
                }
 
                // After a change of child lists caused by a change in the current parent item, we 
                // should reset the list position (a la RelatedCurrencyManager). But we have to do
                // this explicitly, because a CurrencyManager normally tries to preserve its position 
                // after a list reset event.

                // Only reset the position if the list really changed or if the list
                // position is incorrect 
                currentItemChanged = ((null == lastCurrentItem) || (cm.Count == 0) || (lastCurrentItem != cm.Current) || (this.Position >= this.Count));
 
                // Save last current item 
                lastCurrentItem = cm.Count > 0 ? cm.Current : null;
 
                if (currentItemChanged) {
                    this.Position = (this.Count > 0 ? 0 : -1);
                }
            } 

            OnCurrentItemChanged(EventArgs.Empty); 
        } 

        // 
        // ParentCurrencyManager_MetaDataChanged()
        //
        // When the data source signals a change of metadata, we need to re-query for the list specified
        // by the data member field. If the data member is no longer valid under the data source's new 
        // metadata, we have no choice but to clear the data member field and just bind directly to the
        // data source itself. 
        // 
        private void ParentCurrencyManager_MetaDataChanged(object sender, EventArgs e) {
            ClearInvalidDataMember(); 
            ResetList();
        }

        // << Some of this code is taken from System.Data.DataTable::ParseSortString method >> 
        private ListSortDescriptionCollection ParseSortString(string sortString) {
            if (String.IsNullOrEmpty(sortString)) { 
                return new ListSortDescriptionCollection(); 
            }
 
            ArrayList sorts = new ArrayList();
            PropertyDescriptorCollection props = this.currencyManager.GetItemProperties();

            string[] split = sortString.Split(new char[] {','}); 
            for (int i = 0; i < split.Length; i++) {
                string current = split[i].Trim(); 
 
                // Handle ASC and DESC
                int length = current.Length; 
                bool ascending = true;
                if (length >= 5 && String.Compare(current, length - 4, " ASC", 0, 4, true, CultureInfo.InvariantCulture) == 0) {
                    current = current.Substring(0, length - 4).Trim();
                } 
                else if (length >= 6 && String.Compare(current, length - 5, " DESC", 0, 5, true, CultureInfo.InvariantCulture) == 0) {
                    ascending = false; 
                    current = current.Substring(0, length - 5).Trim(); 
                }
 
                // Handle brackets
                if (current.StartsWith("[")) {
                    if (current.EndsWith("]")) {
                        current = current.Substring(1, current.Length - 2); 
                    }
                    else { 
                        throw new ArgumentException(SR.GetString(SR.BindingSourceBadSortString)); 
                    }
                } 

                // Find the property
                PropertyDescriptor prop = props.Find(current, true);
                if (prop == null) { 
                    throw new ArgumentException(SR.GetString(SR.BindingSourceSortStringPropertyNotInIBindingList));
                } 
 
                // Add the sort description
                sorts.Add(new ListSortDescription(prop, ascending ? ListSortDirection.Ascending : ListSortDirection.Descending)); 
            }

            ListSortDescription[] result = new ListSortDescription[sorts.Count];
            sorts.CopyTo(result); 
            return new ListSortDescriptionCollection(result);
        } 
 
        /// 
        public void RemoveCurrent() { 
            if (!(this as IBindingList).AllowRemove) {
                throw new InvalidOperationException(SR.GetString(SR.BindingSourceRemoveCurrentNotAllowed));
            }
 
            if (Position < 0 || Position >= Count) {
                throw new InvalidOperationException(SR.GetString(SR.BindingSourceRemoveCurrentNoCurrentItem)); 
            } 

            RemoveAt(Position); 
        }

        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public virtual void ResetAllowNew() {
            this.allowNewIsSet = false; 
            this.allowNewSetValue = true; 
        }
 
        /// 
        public void ResumeBinding() {
            currencyManager.ResumeBinding(); 
        }
 
        ///  
        public void SuspendBinding() {
            currencyManager.SuspendBinding(); 
        }

        //
        // ResetList() 
        //
        // Binds the BindingSource to the list specified by its DataSource and DataMember properties. 
        // 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] // List is cast to IEnumerable twice. Acceptible trade-off versus code clarity (this method contains *critical* logic).
        private void ResetList() { 

            //
            // Don't bind during initialization, since the data source may not have been initialized yet.
            // Instead, set a flag that causes binding to occur on first post-init attempt to access list. 
            //
            if (this.initializing) { 
                needToSetList = true; 
                return;
            } 
            else {
                needToSetList = false;
            }
 
            //
            // Find the list identified by the current DataSource and DataMember properties. 
            // 
            // If the DataSource only specifies a Type, we actually create an
            // instance from that Type and obtain the list from that instance. 
            //
            // Note: The method below will throw an exception if a data member is specified
            // but does not correspond to a valid property on the data source.
            // 
            object dataSourceInstance = (this.dataSource is Type) ? GetListFromType(this.dataSource as Type) : this.dataSource;
            object list = ListBindingHelper.GetList(dataSourceInstance, this.dataMember); 
            this.listExtractedFromEnumerable = false; 

            // 
            // Convert the candidate list into an IList, if necessary...
            //
            if (list is IList) {
                // If its already an IList then we're done! 
            }
            else if (list is IEnumerable) { 
                // If its an enumerable list, extract its contents and put them in a new list 
                list = GetListFromEnumerable(list as IEnumerable);
                this.listExtractedFromEnumerable = true; 
            }
            else if (list != null) {
                // If its some random non-list object, just wrap it in a list
                list = WrapObjectInBindingList(list); 
            }
            else { 
                // Can't get any list from the data source (eg. data member specifies related sub-list but the 
                // data source's list is empty, so there is no current item to get the sub-list from). In this
                // case we simply determine what the list's item type would be, and create empty list with that 
                // same item type. If the item type cannot be determined, we end up with an item type of 'Object'.
                list = CreateBindingList(ListBindingHelper.GetListItemType(this.dataSource, this.dataMember));
            }
 
            //
            // Bind to this list now 
            // 
            SetList(list as IList, true, true);
        } 

        //
        // SetList()
        // 
        // Binds the BindingSource to the specified list, rewiring internal event handlers,
        // firing any appropriate external events, and updating all relevant field members. 
        // 

        private void SetList(IList list, bool metaDataChanged, bool applySortAndFilter) { 
            if (list == null) {
                // The list argument should never be null! We will handle null gracefully
                // at run-time, but we will complain bitterly about this in debug builds!
                Debug.Fail("BindingSource.SetList() was called with illegal  list argument!"); 
                list = CreateBindingList(this.itemType);
            } 
 
            // Unwire stuff from the old list
            UnwireInnerList(); 
            UnhookItemChangedEventsForOldCurrent();

            // Bind to the new list
            this._innerList = list; 

            // Remember whether the new list implements IBindingList 
            this.isBindingList = (list is IBindingList); 

            // 
            // Determine whether the new list converts PropertyChanged events on its items into ListChanged events.
            // If it does, then the BindingSource won't need to hook the PropertyChanged events itself. If the list
            // implements IRaiseItemChangedEvents, we can ask it directly. Otherwise we will assume that any list
            // which impements IBindingList automatically supports this capability. 
            //
            if (list is IRaiseItemChangedEvents) { 
                this.listRaisesItemChangedEvents = (list as IRaiseItemChangedEvents).RaisesItemChangedEvents; 
            }
            else { 
                this.listRaisesItemChangedEvents = this.isBindingList;
            }

            // If list schema may have changed, update list item info now 
            if (metaDataChanged) {
                this.itemType = ListBindingHelper.GetListItemType(List); 
                this.itemShape = ListBindingHelper.GetListItemProperties(List); 
                this.itemConstructor = this.itemType.GetConstructor(BindingFlags.Public |
                                                                    BindingFlags.Instance | 
                                                                    BindingFlags.CreateInstance,
                                                                    null, new Type[0], null);
            }
 
            // Wire stuff up to the new list
            WireInnerList(); 
            HookItemChangedEventsForNewCurrent(); 

            // Fire list reset and/or metadata changed events 
            ResetBindings(metaDataChanged);

            //
            // Apply any custom Sort and Filter values to the new list. 
            //
            // NOTE: The list will throw a NotSupportedException here if it rejects the new sort 
            // and filter settings (either because it doesn't support sorting and filtering, or 
            // because the sort or filter values were invalid).
            // 
            if (applySortAndFilter) {
                if (this.Sort != null) {
                    this.InnerListSort = this.Sort;
                } 
                if (this.Filter != null) {
                    this.InnerListFilter = this.Filter; 
                } 
            }
        } 

        private static IList WrapObjectInBindingList(object obj) {
            IList list = CreateBindingList(obj.GetType());
            list.Add(obj); 
            return list;
        } 
 
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)] 
        internal virtual bool ShouldSerializeAllowNew() {
            return this.allowNewIsSet;
        }
 
        ///////////////////////////////////////////////////////////////////////////////
        // 
        // ItemChanged event support 
        //
        /////////////////////////////////////////////////////////////////////////////// 

        // Hooks property changed events for the NEW current item, if nececssary
        private void HookItemChangedEventsForNewCurrent() {
            Debug.Assert(this.currentItemHookedForItemChange == null, "BindingSource trying to hook new current item before unhooking old current item!"); 

            if (!this.listRaisesItemChangedEvents) { 
                if (this.Position >= 0 && this.Position <= this.Count - 1) { 
                    this.currentItemHookedForItemChange = this.Current;
                    WirePropertyChangedEvents(this.currentItemHookedForItemChange); 
                }
                else {
                    this.currentItemHookedForItemChange = null;
                } 
            }
        } 
 
        // Unhooks property changed events for the OLD current item, if necessary
        private void UnhookItemChangedEventsForOldCurrent() { 
            if (!this.listRaisesItemChangedEvents) {
                UnwirePropertyChangedEvents(this.currentItemHookedForItemChange);
                this.currentItemHookedForItemChange = null;
            } 
        }
 
        /////////////////////////////////////////////////////////////////////////////// 
        //
        // Event wiring and unwiring methods 
        //
        ///////////////////////////////////////////////////////////////////////////////

        private void WireCurrencyManager(CurrencyManager cm) { 
            if (cm != null) {
                cm.PositionChanged    += new EventHandler(CurrencyManager_PositionChanged); 
                cm.CurrentChanged     += new EventHandler(CurrencyManager_CurrentChanged); 
                cm.CurrentItemChanged += new EventHandler(CurrencyManager_CurrentItemChanged);
                cm.BindingComplete    += new BindingCompleteEventHandler(CurrencyManager_BindingComplete); 
                cm.DataError          += new BindingManagerDataErrorEventHandler(CurrencyManager_DataError);
            }
        }
 
        private void UnwireCurrencyManager(CurrencyManager cm) {
            if (cm != null) { 
                cm.PositionChanged    -= new EventHandler(CurrencyManager_PositionChanged); 
                cm.CurrentChanged     -= new EventHandler(CurrencyManager_CurrentChanged);
                cm.CurrentItemChanged -= new EventHandler(CurrencyManager_CurrentItemChanged); 
                cm.BindingComplete    -= new BindingCompleteEventHandler(CurrencyManager_BindingComplete);
                cm.DataError          -= new BindingManagerDataErrorEventHandler(CurrencyManager_DataError);
            }
        } 

        private void WireDataSource() { 
            if (dataSource is ICurrencyManagerProvider) { 
                CurrencyManager cm  = (dataSource as ICurrencyManagerProvider).CurrencyManager;
                cm.CurrentItemChanged += new EventHandler(ParentCurrencyManager_CurrentItemChanged); 
                cm.MetaDataChanged    += new EventHandler(ParentCurrencyManager_MetaDataChanged);
            }
        }
 
        private void UnwireDataSource() {
            if (dataSource is ICurrencyManagerProvider) { 
                CurrencyManager cm  = (dataSource as ICurrencyManagerProvider).CurrencyManager; 
                cm.CurrentItemChanged -= new EventHandler(ParentCurrencyManager_CurrentItemChanged);
                cm.MetaDataChanged    -= new EventHandler(ParentCurrencyManager_MetaDataChanged); 
            }
        }

        private void WireInnerList() { 
            if (_innerList is IBindingList) {
                IBindingList list = _innerList as IBindingList; 
                list.ListChanged += new ListChangedEventHandler(InnerList_ListChanged); 
            }
        } 

        private void UnwireInnerList() {
            if (_innerList is IBindingList) {
                IBindingList list = _innerList as IBindingList; 
                list.ListChanged -= new ListChangedEventHandler(InnerList_ListChanged);
            } 
        } 

        private void WirePropertyChangedEvents(object item) { 
            if (item != null && this.itemShape != null) {
                for (int j = 0; j < this.itemShape.Count; j++) {
                    this.itemShape[j].AddValueChanged(item, listItemPropertyChangedHandler);
                } 
            }
        } 
 
        private void UnwirePropertyChangedEvents(object item) {
            if (item != null && this.itemShape != null) { 
                for (int j = 0; j < this.itemShape.Count; j++) {
                    this.itemShape[j].RemoveValueChanged(item, listItemPropertyChangedHandler);
                }
            } 
        }
        #endregion Methods 
 
        #region ISupportInitialize/ISupportInitializeNotification
        /////////////////////////////////////////////////////////////////////////////// 
        //
        // ISupportInitialize and ISupportInitializeNotification interfaces
        //
        /////////////////////////////////////////////////////////////////////////////// 

        // Begin bulk member initialization - deferring calculation of inner list until EndInit is reached 
        // 
        void ISupportInitialize.BeginInit() {
            initializing = true; 
        }

        // End bulk member initialization - updating the inner list and notifying any dependents of our completion
        // 
        private void EndInitCore() {
            initializing = false; 
            EnsureInnerList(); 
            OnInitialized();
        } 

        // Check to see if DataSource has completed its initialization, before ending our initialization.
        // If DataSource is still initializing, hook its Initialized event and wait for it to signal completion.
        // If DataSource is already initialized, just go ahead and complete our initialization now. 
        //
        void ISupportInitialize.EndInit() { 
            ISupportInitializeNotification dsInit = (this.DataSource as ISupportInitializeNotification); 

            if (dsInit != null && !dsInit.IsInitialized) { 
                dsInit.Initialized += new EventHandler(DataSource_Initialized);
            }
            else {
                EndInitCore(); 
            }
        } 
 
        // Respond to late completion of the DataSource's initialization, by completing our own initialization.
        // This situation can arise if the call to the DataSource's EndInit() method comes after the call to the 
        // BindingSource's EndInit() method (since code-generated ordering of these calls is non-deterministic).
        //
        private void DataSource_Initialized(object sender, EventArgs e) {
            ISupportInitializeNotification dsInit = (this.DataSource as ISupportInitializeNotification); 

            Debug.Assert(dsInit != null, "BindingSource: ISupportInitializeNotification.Initialized event received, but current DataSource does not support ISupportInitializeNotification!"); 
            Debug.Assert(dsInit.IsInitialized, "BindingSource: DataSource sent ISupportInitializeNotification.Initialized event but before it had finished initializing."); 

            if (dsInit != null) { 
                dsInit.Initialized -= new EventHandler(DataSource_Initialized);
            }

            EndInitCore(); 
        }
 
        // Report to any dependents whether we are still in bulk member initialization 
        //
        bool ISupportInitializeNotification.IsInitialized { 
            get {
                return !initializing;
            }
        } 

        // Event used to signal to our dependents that we have completed bulk member initialization and updated our inner list 
        // 
        event EventHandler ISupportInitializeNotification.Initialized {
            add { 
                Events.AddHandler(EVENT_INITIALIZED, value);
            }
            remove {
                Events.RemoveHandler(EVENT_INITIALIZED, value); 
            }
        } 
 
        // Method used to raise the Initialized event above
        // 
        private void OnInitialized() {
            EventHandler eh = (EventHandler) Events[EVENT_INITIALIZED];
            if (eh != null)
                eh(this, EventArgs.Empty); 
        }
        #endregion ISupportInitialize/ISupportInitializeNotification 
 
        #region IEnumerable
        /////////////////////////////////////////////////////////////////////////////// 
        //
        // IEnumerable interface
        //
        /////////////////////////////////////////////////////////////////////////////// 

        public virtual IEnumerator GetEnumerator() { 
            return List.GetEnumerator(); 
        }
        #endregion 

        #region ICollection
        ///////////////////////////////////////////////////////////////////////////////
        // 
        // ICollection interface
        // 
        /////////////////////////////////////////////////////////////////////////////// 

        public virtual void CopyTo(Array arr, int index) { 
            List.CopyTo(arr, index);
        }

        [Browsable(false)] 
        public virtual int Count {
            get { 
                try 
                {
                    if (disposedOrFinalized) 
                    {
                        return 0;
                    }
                    if (recursionDetectionFlag) 
                    {
                        throw new InvalidOperationException(SR.GetString(SR.BindingSourceRecursionDetected)); 
                    } 
                    recursionDetectionFlag = true;
 
                    return List.Count;
                }
                finally
                { 
                    recursionDetectionFlag = false;
                } 
            } 
        }
 
        [Browsable(false)]
        public virtual bool IsSynchronized
        {
            get { 
                return List.IsSynchronized;
            } 
        } 

        [Browsable(false)] 
        public virtual object SyncRoot {
            get {
                return List.SyncRoot;
            } 
        }
 
        #endregion ICollection 

        #region IList 
        ///////////////////////////////////////////////////////////////////////////////
        //
        // IList interface
        // 
        ///////////////////////////////////////////////////////////////////////////////
 
        /// 
        public virtual object AddNew() { 
            // Throw if adding new items has been disabled
            if (!AllowNewInternal(false)) {
                throw new InvalidOperationException(SR.GetString(SR.BindingSourceBindingListWrapperAddToReadOnlyList));
            } 

            if (!AllowNewInternal(true)) { 
                throw new InvalidOperationException(SR.GetString( 
                    SR.BindingSourceBindingListWrapperNeedToSetAllowNew,
                    itemType == null ? "(null)" : itemType.FullName 
                    ));
            }

            // Remember this since EndEdit() below will clear it 
            int saveAddNew = this.addNewPos;
 
            // Commit any uncomitted list changes now 
            EndEdit();
 
            // We just committed a new item; mimic DataView and fire an ItemAdded event for it here
            if (saveAddNew != -1) {
                OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, saveAddNew));
            } 

            // Raise the AddingNew event in case listeners want to supply the new item for us 
            AddingNewEventArgs addingNew = new AddingNewEventArgs(); 
            int oldCount = List.Count;
            OnAddingNew(addingNew); 
            object addNewItem = addingNew.NewObject;

            //
            // If no item came back from AddingNew event, we must create the new item ourselves... 
            //
            if (addNewItem == null) { 
                // If the inner list is an IBindingList, let it create and add the new item for us. 
                // Then make the new item the current item (...assuming, as CurrencyManager does,
                // that the new item was added at the *bottom* of the list). 
                if (isBindingList) {
                    addNewItem = (List as IBindingList).AddNew();
                    this.Position = this.Count - 1;
                    return addNewItem; 
                }
 
                // Throw if we don't know how to create items of the current item type 
                if (this.itemConstructor == null) {
                    throw new InvalidOperationException(SR.GetString( 
                        SR.BindingSourceBindingListWrapperNeedAParameterlessConstructor,
                        itemType == null ? "(null)" : itemType.FullName
                        ));
                } 

                // Create new item using default ctor for current item type 
                addNewItem = this.itemConstructor.Invoke(null); 
            }
 
            if (List.Count > oldCount) {
                // If event handler has already added item to list, then simply record the item's position
                this.addNewPos = this.Position;
            } 
            else {
                // If event handler has not yet added item to list, then add it 
                // ourselves, make it the current item, and record its position. 
                this.addNewPos = this.Add(addNewItem);
                this.Position = this.addNewPos; 
            }

            return addNewItem;
        } 

        [Browsable(false)] 
        public virtual bool AllowEdit { 
            get {
                if (isBindingList) { 
                    return ((IBindingList) List).AllowEdit;
                }
                else {
                    return !List.IsReadOnly; 
                }
            } 
        } 

        [ 
        SRCategory(SR.CatBehavior),
        SRDescription(SR.BindingSourceAllowNewDescr),
        ]
        ///  
        public virtual bool AllowNew {
            get { 
                //we check to ensure we have a valid default constructor (if we get that far). 
                return AllowNewInternal(true);
            } 

            set {
                // If value was previously set and isn't changing now, do nothing
                if (this.allowNewIsSet && value == this.allowNewSetValue) { 
                    return;
                } 
 
                // Don't let user set value to true if inner list can never support adding of items
                // do NOT check for a default constructor because someone will set AllowNew=True 
                // when they have overridden OnAddingNew (which we cannot detect).
                if (value == true && !isBindingList && !IsListWriteable(false)) {
                    throw new InvalidOperationException(SR.GetString(SR.NoAllowNewOnReadOnlyList));
                } 

                // Record new value, which will now override inner list's value 
                this.allowNewIsSet = true; 
                this.allowNewSetValue = value;
 
                // Mimic the DataView class and fire a list reset event now
                OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
            }
        } 

        [Browsable(false)] 
        public virtual bool AllowRemove { 
            get {
                if (isBindingList) { 
                    return ((IBindingList) List).AllowRemove;
                }
                else {
                    return !List.IsReadOnly && !List.IsFixedSize; 
                }
            } 
        } 

        [Browsable(false)] 
        public virtual bool SupportsChangeNotification {
            get {
                return true;
            } 
        }
 
        [Browsable(false)] 
        public virtual bool SupportsSearching {
            get { 
                if (isBindingList) {
                    return ((IBindingList) List).SupportsSearching;
                }
                else { 
                    return false;
                } 
            } 
        }
 
        [Browsable(false)]
        public virtual bool SupportsSorting {
            get {
                if (isBindingList) { 
                    return ((IBindingList) List).SupportsSorting;
                } 
                else { 
                    return false;
                } 
            }
        }

        [Browsable(false)] 
        public virtual bool IsSorted {
            get { 
                if (isBindingList) { 
                    return ((IBindingList) List).IsSorted;
                } 
                else {
                    return false;
                }
            } 
        }
 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public virtual PropertyDescriptor SortProperty {
            get { 
                if (isBindingList) {
                    return ((IBindingList) List).SortProperty;
                }
                else { 
                    return null;
                } 
            } 
        }
 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public virtual ListSortDirection SortDirection {
            get {
                if (isBindingList) { 
                    return ((IBindingList) List).SortDirection;
                } 
                else { 
                    return ListSortDirection.Ascending;
                } 
            }
        }

        void IBindingList.AddIndex(PropertyDescriptor property) { 
            if (isBindingList) {
                ((IBindingList) List).AddIndex(property); 
            } 
            else {
                throw new NotSupportedException(SR.GetString(SR.OperationRequiresIBindingList)); 
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never)] 
        public virtual void ApplySort(PropertyDescriptor property, ListSortDirection sort) {
            if (isBindingList) { 
                ((IBindingList) List).ApplySort(property, sort); 
            }
            else { 
                throw new NotSupportedException(SR.GetString(SR.OperationRequiresIBindingList));
            }
        }
 
        public virtual int Find(PropertyDescriptor prop, object key) {
            if (isBindingList) { 
                return ((IBindingList) List).Find(prop, key); 
            }
            else { 
                throw new NotSupportedException(SR.GetString(SR.OperationRequiresIBindingList));
            }
        }
 
        void IBindingList.RemoveIndex(PropertyDescriptor prop) {
            if (isBindingList) { 
                ((IBindingList) List).RemoveIndex(prop); 
            }
            else { 
                throw new NotSupportedException(SR.GetString(SR.OperationRequiresIBindingList));
            }
        }
 
        public virtual void RemoveSort() {
            this.sort = null; 
 
            if (isBindingList) {
                ((IBindingList) List).RemoveSort(); 
            }
        }
        #endregion IBindingList
 
        #region IBindingListView
        /////////////////////////////////////////////////////////////////////////////// 
        // 
        // IBindingListView interface
        // 
        ///////////////////////////////////////////////////////////////////////////////

        [EditorBrowsable(EditorBrowsableState.Never)]
        public virtual void ApplySort(ListSortDescriptionCollection sorts) { 
            IBindingListView iblw = List as IBindingListView;
            if (iblw != null) { 
                iblw.ApplySort(sorts); 
            }
            else { 
                throw new NotSupportedException(SR.GetString(SR.OperationRequiresIBindingListView));
            }
        }
 

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public virtual ListSortDescriptionCollection SortDescriptions { 
            get {
                IBindingListView iblw = List as IBindingListView; 
                if (iblw != null) {
                    return iblw.SortDescriptions;
                } else {
                    return null; 
                }
            } 
        } 

        [ 
        SRCategory(SR.CatData),
        DefaultValue(null),
        SRDescription(SR.BindingSourceFilterDescr)
        ] 
        ///