IBindingList Interface
.NET Framework Class Library
IBindingList Interface

Provides the features required to support both complex and simple scenarios when binding to a data source.

Namespace:  System.ComponentModel
Assembly:  System (in System.dll)
Visual Basic (Declaration)
Public Interface IBindingList _
    Inherits IList, ICollection, IEnumerable
Visual Basic (Usage)
Dim instance As IBindingList
C#
public interface IBindingList : IList, 
    ICollection, IEnumerable
Visual C++
public interface class IBindingList : IList, 
    ICollection, IEnumerable
JScript
public interface IBindingList extends IList, ICollection, IEnumerable

This interface is implemented by the DataView class. Implementation of a method should exhibit the same behavior as the implementation of that method in the DataView class.

When you call the ApplySort or RemoveSort methods, you should raise a ListChanged event with the Reset enumeration.

When you call the AddNew method, you should raise a ListChanged event with the ItemAdded enumeration carrying the appropriate index. The added row is in a state where pressing the ESC on a DataGridView control can remove the new row. Raising the ListChanged event with the ItemAdded enumeration a second time on this row indicates that the item is now a row not in the "new" state.

When you remove an item or call the CancelEdit method on a new row (if that row implements IEditableObject), you should raise a ListChanged event with the ItemDeleted enumeration carrying the appropriate index.

The following example provides a simple implementation of the IBindingList interface. The CustomerList class stores customer information in a list. This example assumes that you have used the Customer class that can be found in the example in the IEditableObject class.

Visual Basic
Public Class CustomersList
    Inherits CollectionBase
    Implements IBindingList 

    Private resetEvent As New ListChangedEventArgs(ListChangedType.Reset, -1)
    Private onListChanged1 As ListChangedEventHandler


    Public Sub LoadCustomers()
        Dim l As IList = CType(Me, IList)
        l.Add(ReadCustomer1())
        l.Add(ReadCustomer2())
        OnListChanged(resetEvent)
    End Sub 


    Default Public Property Item(ByVal index As Integer) As Customer
        Get
            Return CType(List(index), Customer)
        End Get
        Set(ByVal Value As Customer)
            List(index) = Value
        End Set
    End Property


    Public Function Add(ByVal value As Customer) As Integer
        Return List.Add(value)
    End Function 


    Public Function AddNew2() As Customer
        Return CType(CType(Me, IBindingList).AddNew(), Customer)
    End Function 


    Public Sub Remove(ByVal value As Customer)
        List.Remove(value)
    End Sub 



    Protected Overridable Sub OnListChanged(ByVal ev As ListChangedEventArgs)
        If (onListChanged1 IsNot Nothing) Then
            onListChanged1(Me, ev)
        End If
    End Sub 



    Protected Overrides Sub OnClear()
        Dim c As Customer
        For Each c In List
            c.parent = Nothing
        Next c
    End Sub 


    Protected Overrides Sub OnClearComplete()
        OnListChanged(resetEvent)
    End Sub 


    Protected Overrides Sub OnInsertComplete(ByVal index As Integer, ByVal value As Object)
        Dim c As Customer = CType(value, Customer)
        c.parent = Me
        OnListChanged(New ListChangedEventArgs(ListChangedType.ItemAdded, index))
    End Sub 


    Protected Overrides Sub OnRemoveComplete(ByVal index As Integer, ByVal value As Object)
        Dim c As Customer = CType(value, Customer)
        c.parent = Me
        OnListChanged(New ListChangedEventArgs(ListChangedType.ItemDeleted, index))
    End Sub 


    Protected Overrides Sub OnSetComplete(ByVal index As Integer, ByVal oldValue As Object, ByVal newValue As Object)
        If oldValue <> newValue Then

            Dim oldcust As Customer = CType(oldValue, Customer)
            Dim newcust As Customer = CType(newValue, Customer)

            oldcust.parent = Nothing
            newcust.parent = Me

            OnListChanged(New ListChangedEventArgs(ListChangedType.ItemAdded, index))
        End If
    End Sub 


    ' Called by Customer when it changes.
    Friend Sub CustomerChanged(ByVal cust As Customer)
        Dim index As Integer = List.IndexOf(cust)
        OnListChanged(New ListChangedEventArgs(ListChangedType.ItemChanged, index))
    End Sub 


    ' Implements IBindingList.

    ReadOnly Property AllowEdit() As Boolean Implements IBindingList.AllowEdit
        Get
            Return True
        End Get
    End Property

    ReadOnly Property AllowNew() As Boolean Implements IBindingList.AllowNew
        Get
            Return True
        End Get
    End Property

    ReadOnly Property AllowRemove() As Boolean Implements IBindingList.AllowRemove
        Get
            Return True
        End Get
    End Property

    ReadOnly Property SupportsChangeNotification() As Boolean Implements IBindingList.SupportsChangeNotification
        Get
            Return True
        End Get
    End Property

    ReadOnly Property SupportsSearching() As Boolean Implements IBindingList.SupportsSearching
        Get
            Return False
        End Get
    End Property

    ReadOnly Property SupportsSorting() As Boolean Implements IBindingList.SupportsSorting
        Get
            Return False
        End Get
    End Property

    ' Events.
    Public Event ListChanged As ListChangedEventHandler Implements IBindingList.ListChanged


    ' Methods.
    Function AddNew() As Object Implements IBindingList.AddNew
        Dim c As New Customer(Me.Count.ToString())
        List.Add(c)
        Return c
    End Function 


    ' Unsupported properties.

    ReadOnly Property IsSorted() As Boolean Implements IBindingList.IsSorted
        Get
            Throw New NotSupportedException()
        End Get
    End Property

    ReadOnly Property SortDirection() As ListSortDirection Implements IBindingList.SortDirection
        Get
            Throw New NotSupportedException()
        End Get
    End Property


    ReadOnly Property SortProperty() As PropertyDescriptor Implements IBindingList.SortProperty
        Get
            Throw New NotSupportedException()
        End Get
    End Property


    ' Unsupported Methods.
    Sub AddIndex(ByVal prop As PropertyDescriptor) Implements IBindingList.AddIndex
        Throw New NotSupportedException()
    End Sub 


    Sub ApplySort(ByVal prop As PropertyDescriptor, ByVal direction As ListSortDirection) Implements IBindingList.ApplySort
        Throw New NotSupportedException()
    End Sub 


    Function Find(ByVal prop As PropertyDescriptor, ByVal key As Object) As Integer Implements IBindingList.Find
        Throw New NotSupportedException()
    End Function 


    Sub RemoveIndex(ByVal prop As PropertyDescriptor) Implements IBindingList.RemoveIndex
        Throw New NotSupportedException()
    End Sub 


    Sub RemoveSort() Implements IBindingList.RemoveSort
        Throw New NotSupportedException()
    End Sub 


    ' Worker functions to populate the list with data.
    Private Shared Function ReadCustomer1() As Customer
        Dim cust As New Customer("536-45-1245")
        cust.FirstName = "Jo"
        cust.LastName = "Brown"
        Return cust
    End Function 


    Private Shared Function ReadCustomer2() As Customer
        Dim cust As New Customer("246-12-5645")
        cust.FirstName = "Robert"
        cust.LastName = "Brown"
        Return cust
    End Function 
End Class

C#
    public class CustomersList :  CollectionBase, IBindingList
    {

        private ListChangedEventArgs resetEvent = new ListChangedEventArgs(ListChangedType.Reset, -1);
        private ListChangedEventHandler onListChanged;

        public void LoadCustomers() 
        {
            IList l = (IList)this;
            l.Add(ReadCustomer1());
            l.Add(ReadCustomer2());
            OnListChanged(resetEvent);
        }

        public Customer this[int index] 
        {
            get 
            {
                return (Customer)(List[index]);
            }
            set 
            {
                List[index] = value;
            }
        }

        public int Add (Customer value) 
        {
            return List.Add(value);
        }

        public Customer AddNew() 
        {
            return (Customer)((IBindingList)this).AddNew();
        }

        public void Remove (Customer value) 
        {
            List.Remove(value);
        }


        protected virtual void OnListChanged(ListChangedEventArgs ev) 
        {
            if (onListChanged != null) 
            {
                onListChanged(this, ev);
            }
        }


        protected override void OnClear() 
        {
            foreach (Customer c in List) 
            {
                c.Parent = null;
            }
        }

        protected override void OnClearComplete() 
        {
            OnListChanged(resetEvent);
        }

        protected override void OnInsertComplete(int index, object value) 
        {
            Customer c = (Customer)value;
            c.Parent = this;
            OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, index));
        }

        protected override void OnRemoveComplete(int index, object value) 
        {
            Customer c = (Customer)value;
            c.Parent = this;
            OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, index));
        }

        protected override void OnSetComplete(int index, object oldValue, object newValue) 
        {
            if (oldValue != newValue) 
            {

                Customer oldcust = (Customer)oldValue;
                Customer newcust = (Customer)newValue;

                oldcust.Parent = null;
                newcust.Parent = this;

                
                OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, index));
            }
        }

        // Called by Customer when it changes.
        internal void CustomerChanged(Customer cust) 
        {
            
            int index = List.IndexOf(cust);

            OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, index));
        }


        // Implements IBindingList.
        bool IBindingList.AllowEdit 
        { 
            get { return true ; }
        }

        bool IBindingList.AllowNew 
        { 
            get { return true ; }
        }

        bool IBindingList.AllowRemove 
        { 
            get { return true ; }
        }

        bool IBindingList.SupportsChangeNotification 
        { 
            get { return true ; }
        }

        bool IBindingList.SupportsSearching 
        { 
            get { return false ; }
        }

        bool IBindingList.SupportsSorting 
        { 
            get { return false ; }
        }


        // Events.
        public event ListChangedEventHandler ListChanged 
        {
            add 
            {
                onListChanged += value;
            }
            remove 
            {
                onListChanged -= value;
            }
        }

        // Methods.
        object IBindingList.AddNew() 
        {
            Customer c = new Customer(this.Count.ToString());
            List.Add(c);
            return c;
        }


        // Unsupported properties.
        bool IBindingList.IsSorted 
        { 
            get { throw new NotSupportedException(); }
        }

        ListSortDirection IBindingList.SortDirection 
        { 
            get { throw new NotSupportedException(); }
        }


        PropertyDescriptor IBindingList.SortProperty 
        { 
            get { throw new NotSupportedException(); }
        }


        // Unsupported Methods.
        void IBindingList.AddIndex(PropertyDescriptor property) 
        {
            throw new NotSupportedException(); 
        }

        void IBindingList.ApplySort(PropertyDescriptor property, ListSortDirection direction) 
        {
            throw new NotSupportedException(); 
        }

        int IBindingList.Find(PropertyDescriptor property, object key) 
        {
            throw new NotSupportedException(); 
        }

        void IBindingList.RemoveIndex(PropertyDescriptor property) 
        {
            throw new NotSupportedException(); 
        }

        void IBindingList.RemoveSort() 
        {
            throw new NotSupportedException(); 
        }

        // Worker functions to populate the list with data.
        private static Customer ReadCustomer1() 
        {
            Customer cust = new Customer("536-45-1245");
            cust.FirstName = "Jo";
            cust.LastName = "Brown";
            return cust;
        }

        private static Customer ReadCustomer2() 
        {
            Customer cust = new Customer("246-12-5645");
            cust.FirstName = "Robert";
            cust.LastName = "Brown";
            return cust;
        }
    }

Visual C++
public ref class CustomersList: public CollectionBase, public IBindingList
{
private:
   ListChangedEventArgs^ resetEvent;
   ListChangedEventHandler^ onListChanged;
   virtual event ListChangedEventHandler^ ListChanged;

public:
   property bool AllowEdit 
   {
      // Implements IBindingList.
      virtual bool get() sealed
      {
         return true;
      }
   }

   virtual property bool AllowNew 
   {
      bool get()
      {
         return true;
      }
   }

   property bool AllowRemove 
   {
      virtual bool get()
      {
         return true;
      }

   }

   property bool SupportsChangeNotification 
   {
      virtual bool get()
      {
         return true;
      }

   }

   property bool SupportsSearching 
   {
      virtual bool get()
      {
         return true;
      }

   }

   property bool SupportsSorting 
   {
      virtual bool get()
      {
         return true;
      }

   }

   // Methods.
   virtual Object^ AddNew()
   {
      Customer^ c = gcnew Customer( this->Count->ToString() );
      List->Add( c );
      return c;
   }


   property bool IsSorted 
   {

      // Unsupported properties.
      virtual bool get()
      {
         throw gcnew NotSupportedException;
         return false;
      }

   }

   property ListSortDirection SortDirection 
   {
      virtual ListSortDirection get()
      {
         throw gcnew NotSupportedException;
         return ListSortDirection::Ascending;
      }

   }

   property PropertyDescriptor^ SortProperty 
   {
      virtual PropertyDescriptor^ get()
      {
         throw gcnew NotSupportedException;
         return nullptr;
      }

   }

   // Unsupported Methods.
   virtual void AddIndex( PropertyDescriptor^ property )
   {
      throw gcnew NotSupportedException;
   }

   virtual void ApplySort( PropertyDescriptor^ property, ListSortDirection direction )
   {
      throw gcnew NotSupportedException;
   }

   virtual int Find( PropertyDescriptor^ property, Object^ key )
   {
      throw gcnew NotSupportedException;
      return 0;
   }

   virtual void RemoveIndex( PropertyDescriptor^ property )
   {
      throw gcnew NotSupportedException;
   }

   virtual void RemoveSort()
   {
      throw gcnew NotSupportedException;
   }


   // Worker functions to populate the list with data.
   static Customer^ ReadCustomer1()
   {
      Customer^ cust = gcnew Customer( "536-45-1245" );
      cust->FirstName = "Jo";
      cust->LastName = "Brown";
      return cust;
   }

   static Customer^ ReadCustomer2()
   {
      Customer^ cust = gcnew Customer( "246-12-5645" );
      cust->FirstName = "Robert";
      cust->LastName = "Brown";
      return cust;
   }

protected:
   virtual void OnListChanged( ListChangedEventArgs^ ev )
   {
      if ( onListChanged != nullptr )
      {
         onListChanged( this, ev );
      }
   }

   virtual void OnClear() override
   {
      List->Clear();
   }

   virtual void OnClearComplete() override
   {
      OnListChanged( resetEvent );
   }

   virtual void OnInsertComplete( int index, Object^ value ) override
   {
      Customer^ c = safe_cast<Customer^>(value);
      c->Parent = this;
      OnListChanged( gcnew ListChangedEventArgs( ListChangedType::ItemAdded,index ) );
   }

   virtual void OnRemoveComplete( int index, Object^ value ) override
   {
      Customer^ c = safe_cast<Customer^>(value);
      c->Parent = this;
      OnListChanged( gcnew ListChangedEventArgs( ListChangedType::ItemDeleted,index ) );
   }

   virtual void OnSetComplete( int index, Object^ oldValue, Object^ newValue ) override
   {
      if ( oldValue != newValue )
      {
         Customer^ oldcust = safe_cast<Customer^>(oldValue);
         Customer^ newcust = safe_cast<Customer^>(newValue);
         oldcust->Parent = 0;
         newcust->Parent = this;
         OnListChanged( gcnew ListChangedEventArgs( ListChangedType::ItemAdded,index ) );
      }
   }

public:

   // Constructor
   CustomersList()
   {
      resetEvent = gcnew ListChangedEventArgs( ListChangedType::Reset,-1 );
   }

   void LoadCustomers()
   {
      IList^ l = static_cast<IList^>(this);
      l->Add( ReadCustomer1() );
      l->Add( ReadCustomer2() );
      OnListChanged( resetEvent );
   }

   property Object^ Item [int]
   {
      Object^ get( int index )
      {
         return static_cast<Customer^>(List->Item[ index ]);
      }

      void set( int index, Object^ value )
      {
         List->Item[ index ] = value;
      }

   }
   int Add( Customer^ value )
   {
      return List->Add( value );
   }

   Customer^ AddNew()
   {
      return safe_cast<Customer^>(static_cast<IBindingList^>(this)->AddNew());
   }

   void Remove( Customer^ value )
   {
      List->Remove( value );
   }

internal:

   // Called by Customer when it changes.
   void CustomerChanged( Customer^ cust )
   {
      int index = List->IndexOf( cust );
      OnListChanged( gcnew ListChangedEventArgs( ListChangedType::ItemChanged,index ) );
   }

};

Windows 7, Windows Vista, Windows XP SP2, Windows XP Media Center Edition, Windows XP Professional x64 Edition, Windows XP Starter Edition, Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, Windows Server 2000 SP4, Windows Millennium Edition, Windows 98, Windows CE, Windows Mobile for Smartphone, Windows Mobile for Pocket PC, Xbox 360, Zune

The .NET Framework and .NET Compact Framework do not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.

.NET Framework

Supported in: 3.5, 3.0, 2.0, 1.1, 1.0

.NET Compact Framework

Supported in: 3.5, 2.0, 1.0

XNA Framework

Supported in: 3.0, 2.0, 1.0
Community Content   What is Community Content?
Add new content RSS  Annotations
Using IBindingList with CollectionBase      Bojan Sala   |   Edit   |   Show History
I'd like to note that above example is actually a very simple approach and could only serve as a learning platform for actual implementation of this highly useful interface.

One major problem I have had while implementing it is with deriving from a CollectionBase class. Even though it is a useful class to save code and time, it already internally implements several interfaces that you cannot therefore fully utilize. For example, it implements Add/Remove methods of IList, so your own Add/Remove logic cannot be part of the interface - instead, any call made from the interface itself, as in code bellow:

((IBindingList)myList).Add();

Would actually call an IList implementation of your CollectionBase class, for example:

myList.List.Add();

This prevents you from controlling add/remove (and few more) methods, but you can use notification overrides which still just serve to notify and cannot prevent anyone from adding or removing items from your collection. Ultimately, actually trying to implement the Add method from IList would result in stack overflow if you use CollectionBase.
Using IBindingList with List      Gil.Y   |   Edit   |   Show History

There is a problem when deriving from IBindingList as it parallel with the List methods:
public class ExampleClass : List<somthing>, IBindingList { ... }
The IBindingList brings the method: public void AddIndex(PropertyDescriptor property) which the programmer need to fill for the binding list interface.
However this was already filled from the List implementation and will create confusion upon runtime as you will see things like Count= cannot evaulte experssion or somthing like that.
To overcome this you will need to explicitly define the IBindingList methods, for example: voidIBindingList.AddIndex(PropertyDescriptor property)

To vs Team -> why not make vs itself to find this overlapping problems at design time, this type of error is nearer to syntax than runtime.

Processing
Page view tracker