- DataGridView Overview
- Basic Data Binding with the DataGridView
- Controlling Modifications to Data in the Grid
- Programmatic DataGridView Construction
- Custom Column Content with Unbound Columns
- Displaying Computed Data in Virtual Mode
- Using the Built-In Column Types
- Built-In Header Cells
- Handling Grid Data Edits
- Automatic Column Sizing
- Column and Row Freezing
- Using the Designer to Define Grids
- Column Reordering
- Defining Custom Column and Cell Types
- Utilizing Cell-Oriented Grid Features
- Formatting with Styles
- Where Are We?
Basic Data Binding with the DataGridView
The easiest way to get started using the DataGridView control is to use it in basic data-binding scenarios. To do this, you first need to obtain a collection of data, typically through your business layer or data access layer. You then set the grid’s data-binding properties to bind to the data collection, as described in Chapters 4 and 5. Just like with other Windows Forms controls, the recommended practice in .NET 2.0 is to always bind your actual client-side data source to an instance of the BindingSource class and then bind your controls to the binding source. The following code shows this process.
private void OnFormLoad(object sender, EventArgs e) { // Create adapter to get data source CustomersTableAdapter adapter = new CustomersTableAdapter(); // Bind table data source to binding source m_CustomersBindingSource.DataSource = adapter.GetData(); // Bind the binding source to grid control m_Grid.DataSource = m_CustomersBindingSource; }
Alternatively, if the binding source is bound to a collection of data collections, such as a data set, then you can refine what part of the data source you want to bind to using the DataMember property:
private void OnFormLoad(object sender, EventArgs e) { // Create adapter to get data source CustomersTableAdapter adapter = new CustomersTableAdapter(); // Get data set instance CustomersDataSet customers = new CustomersDataSet(); // Fill data set adapter.Fill(customers); // Bind binding source to the data set m_CustomersBinding source.DataSource = customers; // Bind grid to the Customers table within the data source m_Grid.DataSource = m_CustomersBinding source; m_Grid.DataMember = "Customers"; }
For basic data-binding scenarios, the DataGridView functions exactly like the DataGrid control did in .NET 1.0, except that the combination of DataSource and DataMember must resolve to a collection of data items, such as a DataTable or object collection. Specifically, they need to resolve to an object that implements the IList interface.
The DataGrid could be bound to a collection of collections, such as a DataSet, and if so, the DataGrid presented hierarchical navigation controls to move through the collections of data. However, this capability was rarely used, partly because the navigation controls that were presented inside the DataGrid were a little unintuitive and could leave the user disoriented. As a result, the Windows Client team that developed the DataGridView control decided not to support hierarchical navigation within the control. The DataGridView is designed to present a single collection of data at a time. You can still achieve an intuitive hierarchical navigation through data, but you will usually use more than one control to do so, adopting a master-details approach as discussed in previous chapters.
The DataSource property can be set to any collection of objects that implements one of four interfaces: IList, IListSource, IBindingList, or IBindingListView. (These interfaces will be discussed in more detail in Chapter 7.) If the data source is itself a collection of data collections, such as a data set or an implementer of IListSource, then the DataMember property must identify which data collection within that source to bind to. If the DataSource property is set to an implementer of IList (from which both IBindingList and IBindingListView derive), then the DataMember property can be null (the default value). When you bind the DataGridView to a binding source, the BindingSource class itself implements IBindingListView (as well as several other data-binding related interfaces), so you can actually bind a grid to any kind of collection that a binding source can work with through a binding source, which includes simple collections that only implement IEnumerable.
Any time the DataSource and/or DataMember properties are set, the grid will iterate through the items found in the data collection and will refresh the data-bound columns of the grid. If the grid is bound to a binding source, any change to the underlying data source to which the binding source is bound also results in the data-bound columns in the grid being refreshed. This happens because of events raised from the binding source to any bound controls whenever its underlying collection changes.
Like most properties on the DataGridView control, any time the DataSource and DataMember properties are set, they fire the DataSourceChanged and DataMemberChanged events, respectively. This lets you hook up code that responds to the data binding that has changed on the grid. You can also react to the DataBindingComplete event, since that will fire after the data source or data member has changed and data binding has been updated. However, if you are trying to monitor changes in the data source, you usually are better off monitoring the corresponding events on the BindingSource component rather than subscribing to the events on the grid itself. This is especially true if the code you are using to handle the event affects other controls on the form. Because you should always bind your controls to a binding source instead of the data source itself if possible, the binding source is the best place to monitor changes in the data source.