Data binding is the process by which a data structure can be attached to a .NET Windows Forms component. Data binding allows you to display and make changes to data from within a Windows Forms component. You can bind Forms controls not just to traditional data sources like a DataSet and DataTable, but also almost to any data structure that contains data. In general, it is not important how data got into the structure. Therefore, you can bind to data that is read from the database, calculated at run time, or read from a file and so on.
With the .NET Framework you have the ability to bind any property on the control to some form of data source. For example:
Windows forms offers two types of data binding - simple binding and complex binding:
Note: Just as you can bind properties of controls to a data source (whether simple- or complex- binding), you can also bind properties of controls to other properties.
Data-binding is used in almost all applications. Example include:
Assuming some certain minimum requirements, data binding in Windows Forms allows you to bind the control to any data source ranging from a database to data in arrays and collections. As a minimum, a bindable data structure must support the IList interface. See Interfaces Related to Data Binding for more information on required interfaces.
The following list of items shows the types of structures and data containers that you can bind to:
It is easier to understand the architecture of Windows Forms data binding from the provider side rather than from the consumer side. Note the following points:
Below is a diagram that summarizes most of the above information:
For example, it is very common to bind a DataTable within a DataSet to .NET DataGrid - (via DataSource and DataMember properties at design-time and via SetDataBinding method at run time. When uses make changes to the grid, changes are automatically saved in the data source (DataTable in this case) - it is Windows Forms Data Binding architecture that writes the values of data-bound controls to the data rows they are bound to.
The CurrenyManager class keeps track of data position within its associated data provider, and as such is used to keep data-bound controls synchronized with each other (showing data from the same record). In .NET, data sources such as DataTable and DataView do not maintain a notion of a control's position within the data contained. Contrast this to ADO where the Recordset maintained a current record and provided methods to navigate to other records (MoveFirst, MoveNext, etc.) While .NET data sources no longer know where the current record is due to the absence of a cursor, multiple positions can be set on the data source
Currency within CurrencyManager is used to refer to the currentness of a position with the data structure. Therefore, an important property on the CurrencyManager is the Position property. The Position property can be used to determine the currency of all controls bound to the same CurrencyManager. For example, assume a DataTable has two columns called FirstName and LastName. Two TextBoxes are bound to the same collection; TextBox 1 is bound to FirstName and TextBox 2 is bound to LastName. When the Position property of the CurrencyManager is set to the nth position, both text boxes will display the appropriate first and last names because they both point to the nth position (but each is bound to a different column).
Each Windows Forms has at least one BindingContext object associated with it to manage one or more CurrnecyManager objects. For each data source, there is a single CurrnecyManager, and because a Windows Forms may have many controls with each control possibly bound to a different data source, there will be multiple CurrnecyManager objects. The purpose of the BindingContext is to manage these CurrnecyManager objects and allow you to retrieve any one of them.
For example, if you add a TextBox control to a form and bind it to a column within a DataTable (i.e., the data source), the TextBox will communicate with the BindingContext associated with that form. The BindingContext in turn talks to the specific CurrencyManager object for that data association. In the example below, two TextBoxes are bound to the same collection; TextBox 1 is bound to FirstName and TextBox 2 is bound to LastName columns within the Customers table in a DataSet.
txtFirstName.DataBindings.Add(
"Text", dataset1, "Customers.FirstName" );
txtLastName.DataBindings.Add( "Text", dataset1, "Customers.LastName"
);
The Control.DataBindings property allows you to retrieve the ControlBindingsCollection, which is the collection of data bindings to a contorl, in order to add a new Binding object to the collection. Control.DataBindings property is used to create Simple Binding.
Note: It is important to be consistent about how a control is bound to a data source. Otherwise, the BindingContext will create multiple CurrencyManager objects resulting in erroneous results. The following code shows two ways to set a data binding. Make sure you are consistent in your code - choose one method and stick with it:
ComboxBox1.DataSource = dataSet1;
ComboxBox1.DisplayMember = "Customers.FirstName";
this.BindingContext[dataSet1, "Customers"].Position = 1;
ComboxBox1.DataSource =
dataSet1.Customers;
ComboxBox1.DisplayMember = "FirstName";
this.BindingContext[dataSet1.Customers].Position = 1;
Controls that are bound to data sources use BindingContext and CurrencyManager objects to navigate through associated data. The following example shows how a handler to a button is used to increment the data position for a specific data binding. This will cause some GUI control (possible a data grid or combo box) to show the next data item(s). Note that setting the Position property beyond the first or last element will not generate an error. To ensure that you remain within the bounds of the collection, include login to test whether you will exceed the data element count:
private void btnNextData_Click( object oSender,
System.EventArgs e )
{
// Get current position and count of
elements
int nPos = this.BindingContext[dataSet1, "authors"].Position;
int nCount = this.BindingContext[dataSet1, "authors"].Count;
// Ensure that we can advance to the
next item
if ( nPos < nCount - 1 )
this.BindingContext[dataSet1, "authors"].Position
+= 1;
}
The CurrencyManager's object PositionChanged event can be used to determine whether the proposed Position value has exceeded the actual data element count.
ADO.NET provides existing data structures (DataTable, etc. ) that support binding to .NET controls. However, the .NET Framework also allows you to create your own data structure classes to support data-binding at different levels of complexity - from basic data-binding to providing design-time support, error checking, and even structured rollback of changes made to data itself.
The following list of interfaces are arranged from least complex to most complex in terms of data-binding support: