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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- OledbConnectionStringbuilder.cs
- LongCountAggregationOperator.cs
- ScrollPattern.cs
- OneOfElement.cs
- GlyphCache.cs
- KeyFrames.cs
- DocumentNUp.cs
- NullToBooleanConverter.cs
- validationstate.cs
- BinaryCommonClasses.cs
- CodePropertyReferenceExpression.cs
- ScrollableControlDesigner.cs
- HttpCachePolicyWrapper.cs
- StyleModeStack.cs
- Rijndael.cs
- DetailsViewModeEventArgs.cs
- XmlIlGenerator.cs
- FlowDocumentScrollViewer.cs
- SystemIPGlobalStatistics.cs
- __Filters.cs
- ToolStripRendererSwitcher.cs
- XPathNavigator.cs
- ReadOnlyPermissionSet.cs
- UserNamePasswordClientCredential.cs
- OleDbException.cs
- IntSecurity.cs
- DocumentPageViewAutomationPeer.cs
- UnionExpr.cs
- DragCompletedEventArgs.cs
- TextDecorationUnitValidation.cs
- ClientTargetSection.cs
- oledbmetadatacollectionnames.cs
- FileChangesMonitor.cs
- SecurityKeyIdentifierClause.cs
- RemotingConfiguration.cs
- ListBoxItemAutomationPeer.cs
- SafeTimerHandle.cs
- ParameterCollection.cs
- documentsequencetextpointer.cs
- HtmlInputReset.cs
- InputProcessorProfiles.cs
- httpapplicationstate.cs
- CoTaskMemHandle.cs
- XmlTypeMapping.cs
- PartitionedStream.cs
- TextParagraphCache.cs
- Function.cs
- FontNameConverter.cs
- Executor.cs
- ResetableIterator.cs
- XmlUtilWriter.cs
- DetailsViewInsertedEventArgs.cs
- ActivityWithResultValueSerializer.cs
- FormConverter.cs
- DrawingContextFlattener.cs
- XPathBinder.cs
- DataKeyCollection.cs
- LinearKeyFrames.cs
- InstanceDataCollectionCollection.cs
- TableChangeProcessor.cs
- ToolConsole.cs
- LogSwitch.cs
- ToolBarTray.cs
- EntityModelBuildProvider.cs
- COM2IManagedPerPropertyBrowsingHandler.cs
- BackEase.cs
- WebServiceResponse.cs
- Misc.cs
- DPCustomTypeDescriptor.cs
- TTSEvent.cs
- Polyline.cs
- RepeatButton.cs
- OdbcConnectionPoolProviderInfo.cs
- DashStyle.cs
- ByeMessage11.cs
- CommonDialog.cs
- CodeDelegateInvokeExpression.cs
- WebRequestModuleElement.cs
- ImageAnimator.cs
- FormatControl.cs
- InlineCollection.cs
- SkipStoryboardToFill.cs
- DeferredTextReference.cs
- OleAutBinder.cs
- MessagePropertyFilter.cs
- KeyInfo.cs
- SerializationFieldInfo.cs
- CreateUserWizard.cs
- CellConstant.cs
- ExceptionHandler.cs
- MouseButton.cs
- GeneralTransform3DTo2DTo3D.cs
- GACMembershipCondition.cs
- TrustLevelCollection.cs
- RectangleF.cs
- _WinHttpWebProxyDataBuilder.cs
- IResourceProvider.cs
- WebBrowsableAttribute.cs
- CommunicationObjectManager.cs
- InternalBase.cs