The Data Binding Model
The key data-driven control in Windows Forms 2.0 is the DataGridView control, the successor to the .NET 1.x DataGrid control.
|Author's Note: The DataGridView control was named GridView in builds earlier than Beta 1.
The DataGridView control provides a very flexible way to display tabular data and you can use it for a variety of purposes. For example, you can use the control to provide a read-only view of a small amount of data. Furthermore, you can successfully employ it to show editable views of larger blocks of data.
|Figure 2: The Actions panel of a DataGridView control in a Windows Form.|
DataGridView controls are highly customizable and not just as far as visual settings are concerned. You can personalize the control beyond imagination with custom behaviors such as a user-defined sorting or your own types of cells. In addition, you can bind it to many types of data stores: local and remote databases, custom business objects, and Web services. The control, though, can also operate with no bound data source.
Let's see what happens when you drag and drop a DataGridView control onto a Windows Form. Figure 2
shows the action panel that displays next to the control once it has been added or selected.
The "Auto Format..." action lets you change the appearance of the control at will by choosing one of several predefined skins. If you're familiar with Visual Studio .NET 2003, this feature is nothing new. You can add a new column or edit the existing ones, and you can enable and disable basic functions such as delete, insert, update, and column reordering. The key operation, though, is assigning the control a data source.
A data source can be a data connector or a local instance of an enumerable data object. More precisely, the DataGridView control accepts any class that implements any of the interfaces in Table 1.
Table 1: Valid interfaces for binding data to a DataGridView control.
An enumerable interface that is typically implemented by arrays, collections, and ADO.NET DataView objects.
The interface supported by classes that provide several views of the data. Classic examples are the ADO.NET DataSet and DataTable classes.
Evolution of the IList interface, IBindingList provides the features required to support both complex and simple scenarios when binding to a data source. A typical class that implements this interface is the generic BindingList<T> class.
Extends the IBindingList interface by providing advanced sorting and filtering capabilities. DataConnector classes implement this interface.
To bind a data source, you simply assign the object to the DataSource
property of the control.
In most cases, you will typically bind the control to a data connector class and bind, in turn, the connector component to another data source or populate it using business objects. In Windows Forms 2.0, the DataConnector component is the favorite data source object because through it you can bind to a variety of data sources. In addition, the DataConnector class is designed to resolve many data binding issues automatically. Let's see how Visual Studio .NET 2005 creates a data connector.
Creating a Connector to the Data
The first time you click to choose the data source of a DataGridView control, the only action you can take is to add a new data source project (see Figure 3
|Figure 3: The dialog box that lets you add a new data source project to the application.|
option lets you define the connection string, select the table to query, and then creates a typed DataSet object in the project to hold the returned data. At the end of the wizard, the Visual Studio 2005 project contains three new objects: a data connector, a typed DataSet, and a custom data adapter. The data adapter will run the query to populate the typed DataSet.
The following code snippet shows the code that is added to the form to make sure the DataSet fills when the form loads.
void Form1_Load(object sender, EventArgs e)
// Fill the DataSet
Note that Visual Studio 2005 creates and manages several .cs
files for each class member of the project. The class that implements the main form, for example, is split over at least two files: form1.cs
. The latter file contains the blocks of code that were hidden in auto-generated regions in Visual Studio .NET 2003. The mechanics of partial classes makes this possible. Note that all the involved files are visible only if you toggle on the "Show All Files" option in the Solution Explorer. Be aware of this if you're going to move files from one folder to another.
The DataConnector control encapsulates the data source for a Windows Form. It binds to a physical data source through the DataSource
properties, as shown below.
// Settings excerpted from form1.designer.cs
EmpDataConnector.DataMember = "Employees";
EmpDataConnector.DataSource = northwindDataSet;
Visual Studio 2005 automatically creates the data connector during the setup of the DataGridView control. However, you can find the control in the toolbox so you can also add it manually.
The data connector monitors the associated data source object. When a change is detected, the bound control is promptly and automatically refreshed. As in Windows Forms 1.x, the Currency Manager object does the monitoring. The CurrentChanged
event handler you see above is added to the form's code in case you want to perform some extra action when the grid (or any other data-bound control) is being refreshed.
As mentioned earlier, you can create a data connector from a variety of sources including Web services, custom data container classes, and local database files such as MDF SQL Server files and MDB Access files. If you choose the Web service option from the dialog in Figure 3
, Visual Studio 2005 runs the Add Web Reference dialog box and lets you locate a Web service locally or remotely. The binding in this case is not direct, but you end up adding a Web service proxy class to the project. Using the methods of the Web service you get a bindable object for the grid.
Finally, you can opt for a custom object. In this case, the object can be part of the project or it can be located through a referenced assembly. In any case, the class must implement any of the interfaces listed in Table 1.