How to: Implement the ITypedList Interface
Implement the ITypedList interface to enable discovery of the schema for a bindable list.
Example
The following code example demonstrates how to implement the ITypedList interface. A generic type named SortableBindingList derives from the BindingList<T> class and implements the ITypedList interface. A simple class named Customer provides data, which is bound to the header of a DataGridView control.
Imports System.ComponentModel
Imports System.Collections.Generic
Imports System.Windows.Forms
<Serializable()> _
Public Class SortableBindingList(Of Tkey)
Inherits BindingList(Of Tkey)
Implements ITypedList
<NonSerialized()> _
Private properties As PropertyDescriptorCollection
Public Sub New()
MyBase.New()
' Get the 'shape' of the list.
' Only get the public properties marked with Browsable = true.
Dim pdc As PropertyDescriptorCollection = TypeDescriptor.GetProperties(GetType(Tkey), New Attribute() {New BrowsableAttribute(True)})
' Sort the properties.
properties = pdc.Sort()
End Sub
#Region "ITypedList Implementation"
Public Function GetItemProperties(ByVal listAccessors() As System.ComponentModel.PropertyDescriptor) As System.ComponentModel.PropertyDescriptorCollection Implements System.ComponentModel.ITypedList.GetItemProperties
Dim pdc As PropertyDescriptorCollection
If (Not (listAccessors Is Nothing)) And (listAccessors.Length > 0) Then
' Return child list shape
pdc = ListBindingHelper.GetListItemProperties(listAccessors(0).PropertyType)
Else
' Return properties in sort order
pdc = properties
End If
Return pdc
End Function
' This method is only used in the design-time framework
' and by the obsolete DataGrid control.
Public Function GetListName( _
ByVal listAccessors() As PropertyDescriptor) As String _
Implements System.ComponentModel.ITypedList.GetListName
Return GetType(Tkey).Name
End Function
#End Region
End Class
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.Collections;
using System.Reflection;
namespace ITypedListCS
{
[Serializable()]
public class SortableBindingList<T> : BindingList<T>, ITypedList
{
[NonSerialized()]
private PropertyDescriptorCollection properties;
public SortableBindingList() : base()
{
// Get the 'shape' of the list.
// Only get the public properties marked with Browsable = true.
PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(
typeof(T),
new Attribute[] { new BrowsableAttribute(true) });
// Sort the properties.
properties = pdc.Sort();
}
#region ITypedList Implementation
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
PropertyDescriptorCollection pdc;
if (listAccessors!=null && listAccessors.Length>0)
{
// Return child list shape.
pdc = ListBindingHelper.GetListItemProperties(listAccessors[0].PropertyType);
}
else
{
// Return properties in sort order.
pdc = properties;
}
return pdc;
}
// This method is only used in the design-time framework
// and by the obsolete DataGrid control.
public string GetListName(PropertyDescriptor[] listAccessors)
{
return typeof(T).Name;
}
#endregion
}
}
Imports System.ComponentModel
Public Class Customer
Implements INotifyPropertyChanged
Public Sub New()
End Sub
Public Sub New(ByVal id As Integer, ByVal name As String, ByVal company As String, ByVal address As String, ByVal city As String, ByVal state As String, ByVal zip As String)
Me._id = id
Me._name = name
Me._company = company
Me._address = address
Me._city = city
Me._state = state
Me._zip = zip
End Sub
#Region "Public Properties"
Private _id As Integer
Public Property ID() As Integer
Get
Return _id
End Get
Set(ByVal value As Integer)
If _id <> value Then
_id = value
OnPropertyChanged(New PropertyChangedEventArgs("ID"))
End If
End Set
End Property
Private _name As String
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
If _name <> value Then
_name = value
OnPropertyChanged(New PropertyChangedEventArgs("Name"))
End If
End Set
End Property
Private _company As String
Public Property Company() As String
Get
Return _company
End Get
Set(ByVal value As String)
If _company <> value Then
_company = value
OnPropertyChanged(New PropertyChangedEventArgs("Company"))
End If
End Set
End Property
Private _address As String
Public Property Address() As String
Get
Return _address
End Get
Set(ByVal value As String)
If _address <> value Then
_address = value
OnPropertyChanged(New PropertyChangedEventArgs("Address"))
End If
End Set
End Property
Private _city As String
Public Property City() As String
Get
Return _city
End Get
Set(ByVal value As String)
If _city <> value Then
_city = value
OnPropertyChanged(New PropertyChangedEventArgs("City"))
End If
End Set
End Property
Private _state As String
Public Property State() As String
Get
Return _state
End Get
Set(ByVal value As String)
If _state <> value Then
_state = value
OnPropertyChanged(New PropertyChangedEventArgs("State"))
End If
End Set
End Property
Private _zip As String
Public Property ZipCode() As String
Get
Return _zip
End Get
Set(ByVal value As String)
If _zip <> value Then
_zip = value
OnPropertyChanged(New PropertyChangedEventArgs("ZipCode"))
End If
End Set
End Property
#End Region
#Region "INotifyPropertyChanged Members"
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)
RaiseEvent PropertyChanged(Me, e)
End Sub
#End Region
End Class
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
namespace ITypedListCS
{
class Customer : INotifyPropertyChanged
{
public Customer() {}
public Customer(int id, string name, string company, string address, string city, string state, string zip)
{
this._id = id;
this._name = name;
this._company = company;
this._address = address;
this._city = city;
this._state = state;
this._zip = zip;
}
#region Public Properties
private int _id;
public int ID
{
get { return _id; }
set
{
if (_id != value)
{
_id = value;
OnPropertyChanged(new PropertyChangedEventArgs("ID"));
}
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
OnPropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
}
private string _company;
public string Company
{
get { return _company; }
set
{
if (_company != value)
{
_company = value;
OnPropertyChanged(new PropertyChangedEventArgs("Company"));
}
}
}
private string _address;
public string Address
{
get { return _address; }
set
{
if (_address != value)
{
_address = value;
OnPropertyChanged(new PropertyChangedEventArgs("Address"));
}
}
}
private string _city;
public string City
{
get { return _city; }
set
{
if (_city != value)
{
_city = value;
OnPropertyChanged(new PropertyChangedEventArgs("City"));
}
}
}
private string _state;
public string State
{
get { return _state; }
set
{
if (_state != value)
{
_state = value;
OnPropertyChanged(new PropertyChangedEventArgs("State"));
}
}
}
private string _zip;
public string ZipCode
{
get { return _zip; }
set
{
if (_zip != value)
{
_zip = value;
OnPropertyChanged(new PropertyChangedEventArgs("ZipCode"));
}
}
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (null != PropertyChanged)
{
PropertyChanged(this, e);
}
}
#endregion
}
}
Imports System.ComponentModel
Imports System.Windows.Forms
Public Class Form1
Inherits System.Windows.Forms.Form
Friend WithEvents flowLayoutPanel1 As FlowLayoutPanel
Friend WithEvents label2 As System.Windows.Forms.Label
Friend WithEvents dataGridView1 As DataGridView
Friend WithEvents button1 As Button
Friend WithEvents button2 As Button
Dim sortableBindingListOfCustomers As SortableBindingList(Of Customer)
Dim bindingListOfCustomers As BindingList(Of Customer)
Public Sub New()
MyBase.New()
Me.InitializeComponent()
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
sortableBindingListOfCustomers = New SortableBindingList(Of Customer)()
bindingListOfCustomers = New BindingList(Of Customer)()
Me.dataGridView1.DataSource = bindingListOfCustomers
End Sub
Private Sub button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles button1.Click
Me.dataGridView1.DataSource = Nothing
Me.dataGridView1.DataSource = sortableBindingListOfCustomers
End Sub
Private Sub button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles button2.Click
Me.dataGridView1.DataSource = Nothing
Me.dataGridView1.DataSource = bindingListOfCustomers
End Sub
'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(Form1))
Me.flowLayoutPanel1 = New System.Windows.Forms.FlowLayoutPanel
Me.label2 = New System.Windows.Forms.Label
Me.dataGridView1 = New System.Windows.Forms.DataGridView
Me.button1 = New System.Windows.Forms.Button
Me.button2 = New System.Windows.Forms.Button
Me.flowLayoutPanel1.SuspendLayout()
CType(Me.dataGridView1, System.ComponentModel.ISupportInitialize).BeginInit()
Me.SuspendLayout()
'
'flowLayoutPanel1
'
Me.flowLayoutPanel1.AutoSize = True
Me.flowLayoutPanel1.Controls.Add(Me.label2)
Me.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Top
Me.flowLayoutPanel1.Location = New System.Drawing.Point(0, 0)
Me.flowLayoutPanel1.Name = "flowLayoutPanel1"
Me.flowLayoutPanel1.Size = New System.Drawing.Size(566, 51)
Me.flowLayoutPanel1.TabIndex = 13
'
'label2
'
Me.label2.AutoSize = True
Me.label2.Location = New System.Drawing.Point(3, 6)
Me.label2.Margin = New System.Windows.Forms.Padding(3, 6, 3, 6)
Me.label2.Name = "label2"
Me.label2.Size = New System.Drawing.Size(558, 39)
Me.label2.TabIndex = 0
Me.label2.Text = "This sample demonstrates how to implement the ITypedList interface. Clicking on the 'Sort Columns' button will bind the DataGridView to a sub-classed BindingList<T> that implements ITypedList to provide a sorted list of columns. Clicking on the 'Reset' button will bind the DataGridView to a normal BindingList<T>."
'
'dataGridView1
'
Me.dataGridView1.AllowUserToAddRows = False
Me.dataGridView1.AllowUserToDeleteRows = False
Me.dataGridView1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
Or System.Windows.Forms.AnchorStyles.Left) _
Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
Me.dataGridView1.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill
Me.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize
Me.dataGridView1.Location = New System.Drawing.Point(6, 57)
Me.dataGridView1.Name = "dataGridView1"
Me.dataGridView1.ReadOnly = True
Me.dataGridView1.RowHeadersVisible = False
Me.dataGridView1.Size = New System.Drawing.Size(465, 51)
Me.dataGridView1.TabIndex = 14
'
'button1
'
Me.button1.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
Me.button1.Location = New System.Drawing.Point(477, 57)
Me.button1.Name = "button1"
Me.button1.Size = New System.Drawing.Size(82, 23)
Me.button1.TabIndex = 15
Me.button1.Text = "Sort Columns"
Me.button1.UseVisualStyleBackColor = True
'
'button2
'
Me.button2.Location = New System.Drawing.Point(477, 86)
Me.button2.Name = "button2"
Me.button2.Size = New System.Drawing.Size(82, 23)
Me.button2.TabIndex = 16
Me.button2.Text = "Reset"
Me.button2.UseVisualStyleBackColor = True
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(566, 120)
Me.Controls.Add(Me.button2)
Me.Controls.Add(Me.button1)
Me.Controls.Add(Me.dataGridView1)
Me.Controls.Add(Me.flowLayoutPanel1)
Me.Name = "Form1"
Me.Text = "ITypedList Sample"
Me.flowLayoutPanel1.ResumeLayout(False)
Me.flowLayoutPanel1.PerformLayout()
CType(Me.dataGridView1, System.ComponentModel.ISupportInitialize).EndInit()
Me.ResumeLayout(False)
Me.PerformLayout()
End Sub
Shared Sub Main()
Application.Run(New Form1())
End Sub
End Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace ITypedListCS
{
public partial class Form1 : Form
{
private SortableBindingList<Customer> sortableBindingListOfCustomers;
private BindingList<Customer> bindingListOfCustomers;
private System.ComponentModel.IContainer components = null;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.Label label2;
private DataGridView dataGridView1;
private Button button1;
private Button button2;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.sortableBindingListOfCustomers = new SortableBindingList<Customer>();
this.bindingListOfCustomers = new BindingList<Customer>();
this.dataGridView1.DataSource = this.bindingListOfCustomers;
}
private void button1_Click(object sender, EventArgs e)
{
this.dataGridView1.DataSource = null;
this.dataGridView1.DataSource = this.sortableBindingListOfCustomers;
}
private void button2_Click(object sender, EventArgs e)
{
this.dataGridView1.DataSource = null;
this.dataGridView1.DataSource = this.bindingListOfCustomers;
}
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.label2 = new System.Windows.Forms.Label();
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.flowLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
// flowLayoutPanel1
//
this.flowLayoutPanel1.AutoSize = true;
this.flowLayoutPanel1.Controls.Add(this.label2);
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Top;
this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(566, 51);
this.flowLayoutPanel1.TabIndex = 13;
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(3, 6);
this.label2.Margin = new System.Windows.Forms.Padding(3, 6, 3, 6);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(558, 39);
this.label2.TabIndex = 0;
this.label2.Text = "This sample demonstrates how to implement the ITypedList interface. Clicking on the 'Sort Columns' button will bind the DataGridView to a sub-classed BindingList<T> that implements ITypedList to provide a sorted list of columns. Clicking on the 'Reset' button will bind the DataGridView to a normal BindingList<T>.";
//
// dataGridView1
//
this.dataGridView1.AllowUserToAddRows = false;
this.dataGridView1.AllowUserToDeleteRows = false;
this.dataGridView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.dataGridView1.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Location = new System.Drawing.Point(6, 57);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.ReadOnly = true;
this.dataGridView1.RowHeadersVisible = false;
this.dataGridView1.Size = new System.Drawing.Size(465, 51);
this.dataGridView1.TabIndex = 14;
//
// button1
//
this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.button1.Location = new System.Drawing.Point(477, 57);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(82, 23);
this.button1.TabIndex = 15;
this.button1.Text = "Sort Columns";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.button2.Location = new System.Drawing.Point(477, 86);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(82, 23);
this.button2.TabIndex = 16;
this.button2.Text = "Reset";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(566, 120);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.dataGridView1);
this.Controls.Add(this.flowLayoutPanel1);
this.Name = "Form1";
this.Text = "ITypedList Sample";
this.Load += new System.EventHandler(this.Form1_Load);
this.flowLayoutPanel1.ResumeLayout(false);
this.flowLayoutPanel1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
Compiling the Code
This example requires:
- References to the System.Drawing and System.Windows.Forms assemblies.
See Also
Concepts
Data Binding and Windows Forms