Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / CompMod / System / ComponentModel / BindingList.cs / 1 / BindingList.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Scope="type", Target="System.ComponentModel.BindingList`1")] namespace System.ComponentModel { using System; using System.Reflection; using System.Collections; using System.Collections.ObjectModel; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Security.Permissions; using CodeAccessPermission = System.Security.CodeAccessPermission; ////// /// [HostProtection(SharedState = true)] [Serializable] public class BindingList: Collection , IBindingList, ICancelAddNew, IRaiseItemChangedEvents { private int addNewPos = -1; private bool raiseListChangedEvents = true; private bool raiseItemChangedEvents = false; [NonSerialized()] private PropertyDescriptorCollection itemTypeProperties = null; [NonSerialized()] private PropertyChangedEventHandler propertyChangedEventHandler = null; [NonSerialized()] private AddingNewEventHandler onAddingNew; [NonSerialized()] private ListChangedEventHandler onListChanged; [NonSerialized()] private int lastChangeIndex = -1; private bool allowNew = true; private bool allowEdit = true; private bool allowRemove = true; private bool userSetAllowNew = false; #region Constructors /// /// /// Default constructor. /// public BindingList() : base() { Initialize(); } ////// /// Constructor that allows substitution of the inner list with a custom list. /// public BindingList(IListlist) : base(list) { Initialize(); } private void Initialize() { // Set the default value of AllowNew based on whether type T has a default constructor this.allowNew = ItemTypeHasDefaultConstructor; // Check for INotifyPropertyChanged if (typeof(INotifyPropertyChanged).IsAssignableFrom(typeof(T))) { // Supports INotifyPropertyChanged this.raiseItemChangedEvents = true; // Loop thru the items already in the collection and hook their change notification. foreach (T item in this.Items) { HookPropertyChanged(item); } } } private bool ItemTypeHasDefaultConstructor { get { Type itemType = typeof(T); if (itemType.IsPrimitive) { return true; } if (itemType.GetConstructor(BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, new Type[0], null) != null) { return true; } return false; } } #endregion #region AddingNew event /// /// /// Event that allows a custom item to be provided as the new item added to the list by AddNew(). /// public event AddingNewEventHandler AddingNew { add { bool allowNewWasTrue = AllowNew; onAddingNew += value; if (allowNewWasTrue != AllowNew) { FireListChanged(ListChangedType.Reset, -1); } } remove { bool allowNewWasTrue = AllowNew; onAddingNew -= value; if (allowNewWasTrue != AllowNew) { FireListChanged(ListChangedType.Reset, -1); } } } ////// /// Raises the AddingNew event. /// protected virtual void OnAddingNew(AddingNewEventArgs e) { if (onAddingNew != null) { onAddingNew(this, e); } } // Private helper method private object FireAddingNew() { AddingNewEventArgs e = new AddingNewEventArgs(null); OnAddingNew(e); return e.NewObject; } #endregion #region ListChanged event ////// /// Event that reports changes to the list or to items in the list. /// public event ListChangedEventHandler ListChanged { add { onListChanged += value; } remove { onListChanged -= value; } } ////// /// Raises the ListChanged event. /// protected virtual void OnListChanged(ListChangedEventArgs e) { if (onListChanged != null) { onListChanged(this, e); } } ////// /// public void ResetBindings() { FireListChanged(ListChangedType.Reset, -1); } ////// /// public void ResetItem(int position) { FireListChanged(ListChangedType.ItemChanged, position); } // Private helper method private void FireListChanged(ListChangedType type, int index) { if (this.raiseListChangedEvents) { OnListChanged(new ListChangedEventArgs(type, index)); } } #endregion #region Collectionoverrides // Collection funnels all list changes through the four virtual methods below. // We override these so that we can commit any pending new item and fire the proper ListChanged events. protected override void ClearItems() { EndNew(addNewPos); if (this.raiseItemChangedEvents) { foreach (T item in this.Items) { UnhookPropertyChanged(item); } } base.ClearItems(); FireListChanged(ListChangedType.Reset, -1); } protected override void InsertItem(int index, T item) { EndNew(addNewPos); base.InsertItem(index, item); if (this.raiseItemChangedEvents) { HookPropertyChanged(item); } FireListChanged(ListChangedType.ItemAdded, index); } protected override void RemoveItem(int index) { // Need to all RemoveItem if this on the AddNew item if (!this.allowRemove && !(this.addNewPos >= 0 && this.addNewPos == index)) { throw new NotSupportedException(); } EndNew(addNewPos); if (this.raiseItemChangedEvents) { UnhookPropertyChanged(this[index]); } base.RemoveItem(index); FireListChanged(ListChangedType.ItemDeleted, index); } protected override void SetItem(int index, T item) { if (this.raiseItemChangedEvents) { UnhookPropertyChanged(this[index]); } base.SetItem(index, item); if (this.raiseItemChangedEvents) { HookPropertyChanged(item); } FireListChanged(ListChangedType.ItemChanged, index); } #endregion #region ICancelAddNew interface /// /// /// If item added using AddNew() is still cancellable, then remove that item from the list. /// public virtual void CancelNew(int itemIndex) { if (addNewPos >= 0 && addNewPos == itemIndex) { RemoveItem(addNewPos); addNewPos = -1; } } ////// /// If item added using AddNew() is still cancellable, then commit that item. /// public virtual void EndNew(int itemIndex) { if (addNewPos >= 0 && addNewPos == itemIndex) { addNewPos = -1; } } #endregion #region IBindingList interface ////// /// Adds a new item to the list. Calls public T AddNew() { return (T)((this as IBindingList).AddNew()); } object IBindingList.AddNew() { // Create new item and add it to list object newItem = AddNewCore(); // Record position of new item (to support cancellation later on) addNewPos = (newItem != null) ? IndexOf((T) newItem) : -1; // Return new item to caller return newItem; } private bool AddingNewHandled { get { return onAddingNew != null && onAddingNew.GetInvocationList().Length > 0; } } ///to create and add the item. /// /// Add operations are cancellable via the interface. The position of the /// new item is tracked until the add operation is either cancelled by a call to , /// explicitly commited by a call to , or implicitly commmited some other operation /// that changes the contents of the list (such as an Insert or Remove). When an add operation is /// cancelled, the new item is removed from the list. /// /// /// Creates a new item and adds it to the list. /// /// The base implementation raises the AddingNew event to allow an event handler to /// supply a custom item to add to the list. Otherwise an item of type T is created. /// The new item is then added to the end of the list. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2113:SecureLateBindingMethods")] protected virtual object AddNewCore() { // Allow event handler to supply the new item for us object newItem = FireAddingNew(); // If event hander did not supply new item, create one ourselves if (newItem == null) { Type type = typeof(T); newItem = SecurityUtils.SecureCreateInstance(type); } // Add item to end of list. Note: If event handler returned an item not of type T, // the cast below will trigger an InvalidCastException. This is by design. Add((T) newItem); // Return new item to caller return newItem; } ////// /// public bool AllowNew { get { //If the user set AllowNew, return what they set. If we have a default constructor, allowNew will be //true and we should just return true. if (userSetAllowNew || allowNew) { return this.allowNew; } //Even if the item doesn't have a default constructor, the user can hook AddingNew to provide an item. //If there's a handler for this, we should allow new. return AddingNewHandled; } set { bool oldAllowNewValue = AllowNew; userSetAllowNew = true; //Note that we don't want to set allowNew only if AllowNew didn't match value, //since AllowNew can depend on onAddingNew handler this.allowNew = value; if (oldAllowNewValue != value) { FireListChanged(ListChangedType.Reset, -1); } } } /* private */ bool IBindingList.AllowNew { get { return AllowNew; } } ////// /// public bool AllowEdit { get { return this.allowEdit; } set { if (this.allowEdit != value) { this.allowEdit = value; FireListChanged(ListChangedType.Reset, -1); } } } /* private */ bool IBindingList.AllowEdit { get { return AllowEdit; } } ////// /// public bool AllowRemove { get { return this.allowRemove; } set { if (this.allowRemove != value) { this.allowRemove = value; FireListChanged(ListChangedType.Reset, -1); } } } /* private */ bool IBindingList.AllowRemove { get { return AllowRemove; } } bool IBindingList.SupportsChangeNotification { get { return SupportsChangeNotificationCore; } } protected virtual bool SupportsChangeNotificationCore { get { return true; } } bool IBindingList.SupportsSearching { get { return SupportsSearchingCore; } } protected virtual bool SupportsSearchingCore { get { return false; } } bool IBindingList.SupportsSorting { get { return SupportsSortingCore; } } protected virtual bool SupportsSortingCore { get { return false; } } bool IBindingList.IsSorted { get { return IsSortedCore; } } protected virtual bool IsSortedCore { get { return false; } } PropertyDescriptor IBindingList.SortProperty { get { return SortPropertyCore; } } protected virtual PropertyDescriptor SortPropertyCore { get { return null; } } ListSortDirection IBindingList.SortDirection { get { return SortDirectionCore; } } protected virtual ListSortDirection SortDirectionCore { get { return ListSortDirection.Ascending; } } void IBindingList.ApplySort(PropertyDescriptor prop, ListSortDirection direction) { ApplySortCore(prop, direction); } protected virtual void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction) { throw new NotSupportedException(); } void IBindingList.RemoveSort() { RemoveSortCore(); } protected virtual void RemoveSortCore() { throw new NotSupportedException(); } int IBindingList.Find(PropertyDescriptor prop, object key) { return FindCore(prop, key); } protected virtual int FindCore(PropertyDescriptor prop, object key) { throw new NotSupportedException(); } void IBindingList.AddIndex(PropertyDescriptor prop) { // Not supported } void IBindingList.RemoveIndex(PropertyDescriptor prop) { // Not supported } #endregion #region Property Change Support private void HookPropertyChanged(T item) { INotifyPropertyChanged inpc = (item as INotifyPropertyChanged); // Note: inpc may be null if item is null, so always check. if (null != inpc) { if (propertyChangedEventHandler == null) { propertyChangedEventHandler = new PropertyChangedEventHandler(Child_PropertyChanged); } inpc.PropertyChanged += propertyChangedEventHandler; } } private void UnhookPropertyChanged(T item) { INotifyPropertyChanged inpc = (item as INotifyPropertyChanged); // Note: inpc may be null if item is null, so always check. if (null != inpc && null != propertyChangedEventHandler) { inpc.PropertyChanged -= propertyChangedEventHandler; } } void Child_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (this.RaiseListChangedEvents) { if (sender == null || e == null || string.IsNullOrEmpty(e.PropertyName)) { // Fire reset event (per INotifyPropertyChanged spec) ResetBindings(); } else { // The change event is broken should someone pass an item to us that is not // of type T. Still, if they do so, detect it and ignore. It is an incorrect // and rare enough occurrence that we do not want to slow the mainline path // with "is" checks. T item; try { item = (T)sender; } catch(InvalidCastException) { ResetBindings(); return; } // Find the position of the item. This should never be -1. If it is, // somehow the item has been removed from our list without our knowledge. int pos = lastChangeIndex; if (pos < 0 || pos >= Count || !this[pos].Equals(item)) { pos = this.IndexOf(item); lastChangeIndex = pos; } if (pos == -1) { Debug.Fail("Item is no longer in our list but we are still getting change notifications."); UnhookPropertyChanged(item); ResetBindings(); } else { // Get the property descriptor if (null == this.itemTypeProperties) { // Get Shape itemTypeProperties = TypeDescriptor.GetProperties(typeof(T)); Debug.Assert(itemTypeProperties != null); } PropertyDescriptor pd = itemTypeProperties.Find(e.PropertyName, true); // Create event args. If there was no matching property descriptor, // we raise the list changed anyway. ListChangedEventArgs args = new ListChangedEventArgs(ListChangedType.ItemChanged, pos, pd); // Fire the ItemChanged event OnListChanged(args); } } } } #endregion #region IRaiseItemChangedEvents interface ////// /// Returns false to indicate that BindingList bool IRaiseItemChangedEvents.RaisesItemChangedEvents { get { return this.raiseItemChangedEvents; } } #endregion } }does NOT raise ListChanged events /// of type ItemChanged as a result of property changes on individual list items /// unless those items support INotifyPropertyChanged ///
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- TCPListener.cs
- XmlCountingReader.cs
- PaperSource.cs
- AudioFileOut.cs
- BoolLiteral.cs
- FolderBrowserDialog.cs
- AspProxy.cs
- TemplateControlParser.cs
- XmlSchemas.cs
- ProfileSection.cs
- StringSource.cs
- SliderAutomationPeer.cs
- ObjectDataSourceSelectingEventArgs.cs
- RowType.cs
- LinkLabel.cs
- WrappedReader.cs
- MessageDecoder.cs
- XmlBinaryReader.cs
- _LazyAsyncResult.cs
- Comparer.cs
- XPathDescendantIterator.cs
- CngKeyCreationParameters.cs
- RowVisual.cs
- ApplicationManager.cs
- ContextStack.cs
- RecognizerStateChangedEventArgs.cs
- ErrorLog.cs
- MSAAEventDispatcher.cs
- TextProperties.cs
- OpenFileDialog.cs
- CodeExporter.cs
- PolyBezierSegmentFigureLogic.cs
- SignalGate.cs
- ByteConverter.cs
- MatcherBuilder.cs
- StyleSelector.cs
- DropDownList.cs
- DataGridViewCellValueEventArgs.cs
- GACIdentityPermission.cs
- HttpPostedFile.cs
- GridViewRowEventArgs.cs
- StatusBarPanelClickEvent.cs
- ResourcesBuildProvider.cs
- SmiMetaData.cs
- RelatedView.cs
- InertiaTranslationBehavior.cs
- MostlySingletonList.cs
- BindingNavigatorDesigner.cs
- HttpResponseMessageProperty.cs
- TableLayoutColumnStyleCollection.cs
- IdnMapping.cs
- DynamicScriptObject.cs
- MemberNameValidator.cs
- TextTreeTextNode.cs
- FunctionDefinition.cs
- TrackingProfileManager.cs
- JournalEntry.cs
- COM2FontConverter.cs
- ItemList.cs
- ConnectionConsumerAttribute.cs
- SystemGatewayIPAddressInformation.cs
- HelpInfo.cs
- TypeToStringValueConverter.cs
- TakeQueryOptionExpression.cs
- FileDialogCustomPlacesCollection.cs
- FileDialogCustomPlace.cs
- BaseResourcesBuildProvider.cs
- SymbolEqualComparer.cs
- DbConnectionPoolCounters.cs
- PrivilegeNotHeldException.cs
- XmlObjectSerializerWriteContextComplex.cs
- NativeObjectSecurity.cs
- HttpRuntime.cs
- SoapFormatExtensions.cs
- CollectionChange.cs
- PrivilegedConfigurationManager.cs
- CharAnimationUsingKeyFrames.cs
- SqlDependencyUtils.cs
- OutputCacheProfile.cs
- OdbcConnectionPoolProviderInfo.cs
- ZoneButton.cs
- ReadOnlyNameValueCollection.cs
- DeferredSelectedIndexReference.cs
- StopStoryboard.cs
- AnnotationComponentChooser.cs
- ADRoleFactory.cs
- SHA256Managed.cs
- TreeView.cs
- DelayedRegex.cs
- RoutedEventValueSerializer.cs
- PrimitiveSchema.cs
- SplineKeyFrames.cs
- DocumentEventArgs.cs
- Int32.cs
- ReadOnlyDictionary.cs
- SqlReferenceCollection.cs
- StreamAsIStream.cs
- ToolStripArrowRenderEventArgs.cs
- Avt.cs
- JsonWriter.cs