Windows Forms Data Binding

One of the most powerful aspects of .NET and Windows Forms is data binding. Historically, data binding was used to bind views to data stored in databases. Some database management systems, such as Microsoft Access, have provided GUI APIs to help developers quickly bind to data.

 

This sample is taken from Chapter 6: "Windows Forms Data Binding" of the Blue Vision Title "Developing .NET Custom Controls and Designers using C#"


IDataErrorInfo

This interface offers custom error information that controls can bind to. During data binding, this allows controls to retrieve specific error information from the data source itself. For instance, if a particular column in a DataTable is an Integer type, setting a field to a string for this column will cause the data source to return an appropriate error. This interface provides to properties:

Error: Returns an error message indicating what is wrong.

Item: An indexer that gets the error message for the specified column name or property name.

Complex Binding Example

In the last section, we saw how to implement simple binding. We discussed how to bind public properties of controls to properties of objects and columns of DataTable objects, and synchronize the data, one item at a time. But there are also situations where an entire collection of data needs to be bound, such as viewing a list of software bugs. Typical controls that support such complex data binding include the DataGrid, ListBox, ComboBox, and ErrorProvider controls.

All complex data bound controls will expose two important properties: DataSource and DataMember. The DataSource property can be any type derived from the interfaces discussed earlier. The DataMember is a string containing either the table name or a public property to bind to. For example, if the DataSource is a DataSet, the DataMember should specify which table to bind to; if the DataSource is a collection, the DataMember should be null; and if the DataSource is an object that has the binding collection as one of its public properties, the DataMember will be the name of that property.

In this example, we will utilize the DataGrid to bind to the array of customers used in the previous simple binding example.

First, drag the DataGrid control from the toolbox to the form that you created in the simple binding example. Also, drag another set of navigation buttons to the form. Each set of navigation buttons should correspond to a group box, and hence, a BindingContext. The DataGrid will display the entire list of customers (which is only three items for this example). We also want to use the row navigation events of the grid to change the current item in the first group box. You will have to rearrange the controls and resize the form as shown:

Also, in order to tackle another bird with this stone, add a PropertyGrid control to the form. The PropertyGrid is not added to the toolbox by default, so right-click the toolbox, click "Customize Toolbox&," navigate to the .NET Framework Components tab, and select the PropertyGrid control. The PropertyGrid will be synchronized with the current item in the list, displaying that items properties. The PropertyGrid control should be placed on the form as shown:

Name your controls as follows:

DataGrid: _dataGrid

PropertyGrid: _propertyGrid

Now, using the code from the simple binding example, add two these lines to the constructor:

_dataGrid1.DataSource = _customers;

_propertyGrid1.DataBindings.Add("SelectedObject",

                  _groupBox1.BindingContext [_customers], "Current");

Here is a breakdown of what is happening with this code. First, we set the DataSource property of the data grid to the Customers collection. Since this is the collection we want to bind to, there is no need to set the DataMember property. Next, we synchronize the PropertyGrid  with the current customer of the first group box. The PropertyGrid exposes a property, SelectedObject, which is used to display all public browsable properties of an object.

Now compile and run the sample. Notice that by clicking the navigation buttons of the first group box, the PropertyGrid  automatically updates its display for the new current object. It does this with only one line of code. But there is one small problem: Selecting different rows of the DataGrid does not cause navigation in the first group box that we expected. By now, you should already know what the problem is. Its the BindingContext. Since we did not explicitly assign a BindingContext to the DataGrid, it will use the Form's default BindingContext. And in this example, the Form's default BindingContext isn't managing any data bindings. To get around this problem, we simply assign the BindingContext of _groupBox1 to the BindingContext of the DataGrid, as shown:

_groupBox1.BindingContext  = new BindingContext();

_groupBox2.BindingContext  = new BindingContext();

&

_dataGrid1.DataSource = _customers;

_dataGrid1.BindingContext  = _groupBox1.BindingContext;

Now if we run the code, navigation will work as expected, with only one extra line of code. The full constructor is shown below:

privatereadonly Customer[] _customers = null;

public Form1()

  {

      InitializeComponent();

      _customers = new Customer[]

            {

                  new Customer("James", "Henry", "123-123-1234"),

                  new Customer("Bill", "Gates", "234-234-2345"),

                 new Customer("Tupac", "Shakur", "777-777-7777"),

            }

      _groupBox1.BindingContext = new BindingContext();

      _groupBox2.BindingContext = new BindingContext();

     _dataGrid1.DataSource = _customers;

      _dataGrid1.BindingContext  = _groupBox1.BindingContext;

      _propertyGrid1.DataBindings.Add("SelectedObject",

                        _groupBox1.BindingContext [_customers], "Current");

      _firstNameTextBox.DataBindings.Add("Text", _customers, "FirstName");

      _lastNameTextBox.DataBindings.Add("Text", _customers, "LastName");

      _phoneNumberTextBox.DataBindings.Add("Text", _customers, "PhoneNumber");

     _firstNameTextBox2.DataBindings.Add("Text", _customers, "FirstName");

      _lastNameTextBox2.DataBindings.Add("Text", _customers, "LastName");

      _phoneNumberTextBox2.DataBindings.Add("Text", _customers, "PhoneNumber");

  }

Comments

Be the first to write a comment

You must me logged in to write a comment.