ARTICLE

Data Binding in DataGrid Control using C#

Posted by John Hudai Godel Articles | ADO.NET February 17, 2004
The ADO.NET DataSet is a data construct that can contain several relational rowsets, the relations that link those rowsets, and the metadata for each rowset. The DataSet also tracks which fields have changed, their new values and their original values, and can store custom information in its Extended Properties collection. The DataSet can be exported to XML or created from an XML document, thus enabling increased interoperability between applications.
Reader Level:


Additional words to DataGrid

A DataGrid control is a control that is displays ADO.NET data in a scrollable grid. The System.Windows.Forms.DataGrid (windows form) displays web-like links to child tables. You can click on a link to navigate to the child table. When a child table is displayed, a back button appears in the caption that can be clicked to navigate back to the parent table. The data from the parent rows is displayed below the caption and above the column headers. You can hide the parent row information by clicking the button to the right of the back button.


To display a table in the System.Windows.Forms.DataGrid at run time, use the SetDataBinding method to set the DataSource and DataMember properties to a valid data source. The following data sources are valid: 

  •  A DataTable 
  •  A DataView 
  •  A DataSet 
  •  A DataViewManager 
  •  A single dimension array 
  •  Any component that implements the IListSource interface 
  •  Any component that implements the IList interface

Data sources are further managed by BindingManagerBase objects. For each table in a data source, a BindingManagerBase can be returned from the form's BindingContext. For example, you can determine the number of rows contained by a data source by returning the associated BindingManagerBase object's Count Property.

To validate data, use the underlying objects that represent data and their events. For example, if the data comes from a DataTable in a DataSet, use the ColumnChanging and RowChanging events. Note Because the number of columns can be customized (by adding or deleting members of the GridColumnStylesCollection) and the rows may be sorted by column, the RowNumber and ColumnNumber property values cannot be guaranteed to correspond to DataRow and DataColumn indexes in a DataTable. Therefore you should avoid using those properties in the Validating event to validate data.

To determine which cell is selected, use the CurrentCell property. Change the value of any cell by using the Item property, which can take both the row and column indexes of the cell, or a single DataGridCell. Monitor the CurrentCellChanged event to detect when the user selects another cell. To determine which part of the control the user clicked, use the HitTest method in the MouseDown event. The HitTest method returns a DataGrid.HitTestInfo object, which contains the row and column of a clicked area.

To manage the appearance of the control at run time, several properties for setting the color and caption attributes are available, including the CaptionForeColor, CaptionBackColor, CaptionFont, and so on. The appearance of the displayed grid (or grids) can be further modified by creating DataGridTableStyle objects and adding them to the GridTableStylesCollection, which is accessed through the TableStyles property. For example, if the DataSource is set to a DataSet containing three DataTable objects, you can add three DataGridTableStyle objects to the collection, one for each table. To synchronize each DataGridTableStyle object with a DataTable, set the MappingName of the DataGridTableStyle to the TableName of the DataTable.

To create a customized view of a table, create a collection of DataGridColumnStyle objects, and set each column's MappingName to the ColumnName of a column that you want to show in the grid. To hide a column, set its MappingName to something other than a valid ColumnName. For each DataGridTableStyle, you can set color and caption attributes that override the settings for the System.Windows.Forms.DataGrid control. However, if those properties are not set, the settings for the control are used by default. The following properties can be overridden by DataGridTableStyle properties:
  •  AllowSorting 
  •  AlternatingBackColor 
  •  BackColor 
  •  ColumnHeadersVisible 
  •  ForeColor 
  •  GridLineColor 
  •  GridLineStyle 
  •  HeaderBackColor 
  •  HeaderFont 
  •  HeaderForeColor 
  •  LinkColor 
  •  PreferredColumnWidth 
  •  PreferredRowHeight 
  •  ReadOnly 
  •  RowHeadersVisible 
  •  RowHeaderWidth 
  •  SelectionBackColor 
  •  SelectionForeColor

To customize the appearance of individual columns, add DataGridColumnStyle objects to the GridColumnStylesCollection, which is accessed through the GridColumnStyles property of each DataGridTableStyle. To synchronize each DataGridColumnStyle with a DataColumn in the DataTable, set the MappingName to the ColumnName of a DataColumn. When constructing a DataGridColumnStyle, you can also set a formatting string that specifies how the column displays data. For example, you can specify that the column use a short-date format to display dates contained in the table.

Please pay attention to you need always create DataGridColumnStyle objects and add them to the GridColumnStylesCollection before adding DataGridTableStyle objects to the GridTableStylesCollection. When you add an empty DataGridTableStyle to the collection, DataGridColumnStyle objects are automatically generated for you. Consequently, an exception will be thrown if you try to add new DataGridColumnStyle objects with duplicate MappingName values to the GridColumnStylesCollection.
The following example creates a Windows form, a DataSet containing two DataTable objects, and a DataRelation that relates the two tables. To display the data, a System.Windows.Forms.DataGrid control is then bound to the DataSet through the SetDataBinding method. A button on the form changes the appearance of the grid by creating two DataGridTableStyle objects and setting the MappingName of each object to a TableName of one of the DataTable objects. The example also contains code in the MouseUp event that uses the HitTest method to print the column, row, and part of the grid that has been clicked.

using
System;
using
System.ComponentModel;
using
System.Data;
using
System.Drawing;
using
System.Windows.Forms;
public class
Form1 : System.Windows.Forms.Form
{
private
System.ComponentModel.Container components;
private
Button button1;
private
Button button2;
private
DataGrid myDataGrid;
private
DataSet myDataSet;
private bool
TablesAlreadyAdded;
public
Form1()
{
// Required for Windows Form Designer support.
InitializeComponent();
// Call SetUp to bind the controls.
SetUp();
}
protected override void Dispose( bool
disposing )
{
if
( disposing )
{
if (components != null
)
{
components.Dispose();}
}
base
.Dispose( disposing );
}
private void
InitializeComponent()
{
// Create the form and its controls.
this.components = new
System.ComponentModel.Container();
this.button1 = new
System.Windows.Forms.Button();
this.button2 = new
System.Windows.Forms.Button();
this.myDataGrid = new
DataGrid();
this.AutoScaleBaseSize = new
System.Drawing.Size(5, 13);
this
.Text = "DataGrid Control Sample";
this.ClientSize = new
System.Drawing.Size(450, 330);
button1.Location =
new
Point(24, 16);
button1.Size =
new
System.Drawing.Size(120, 24);
button1.Text = "Change Appearance";
button1.Click+=
new
System.EventHandler(button1_Click);
button2.Location =
new
Point(150, 16);
button2.Size = new
System.Drawing.Size(120, 24);
button2.Text = "Get Binding Manager";
button2.Click+=
new
System.EventHandler(button2_Click);
myDataGrid.Location =
new
Point(24, 50);
myDataGrid.Size =
new
Size(300, 200);
myDataGrid.CaptionText = "Microsoft DataGrid Control";
myDataGrid.MouseUp +=
new
MouseEventHandler(Grid_MouseUp);
this
.Controls.Add(button1);
this
.Controls.Add(button2);
this
.Controls.Add(myDataGrid);
}
public static void
Main()
Application.Run(
new
Form1());
}
private void
SetUp()
{
// Create a DataSet with two tables and one relation.
MakeDataSet();
/* Bind the DataGrid to the DataSet. The dataMember
specifies that the Customers table should be displayed.*/
myDataGrid.SetDataBinding(myDataSet, "Customers");
}
protected void button1_Click(object
sender, System.EventArgs e)
{
if(TablesAlreadyAdded) return
;AddCustomDataTableStyle();
}
private void
AddCustomDataTableStyle()
{
DataGridTableStyle ts1 =
new
DataGridTableStyle();
ts1.MappingName = "Customers";
// Set other properties.
ts1.AlternatingBackColor = Color.LightGray;
/* Add a GridColumnStyle and set its MappingName
to the name of a DataColumn in the DataTable.
Set the HeaderText and Width properties. */
DataGridColumnStyle boolCol = new
DataGridBoolColumn();
boolCol.MappingName = "Current";
boolCol.HeaderText = "IsCurrent Customer";
boolCol.Width = 150;
ts1.GridColumnStyles.Add(boolCol);
// Add a second column style.
DataGridColumnStyle TextCol = new
DataGridTextBoxColumn();
TextCol.MappingName = "custName";
TextCol.HeaderText = "Customer Name";
TextCol.Width = 250;ts1.GridColumnStyles.Add(TextCol);
// Create the second table style with columns.
DataGridTableStyle ts2 = new
DataGridTableStyle();
ts2.MappingName = "Orders";
// Set other properties.
ts2.AlternatingBackColor = Color.LightBlue;
// Create new ColumnStyle objects
DataGridColumnStyle cOrderDate =
new
DataGridTextBoxColumn();
cOrderDate.MappingName = "OrderDate";
cOrderDate.HeaderText = "Order Date";
cOrderDate.Width = 100;
ts2.GridColumnStyles.Add(cOrderDate);
/* Use a PropertyDescriptor to create a formatted
column. First get the PropertyDescriptorCollection
for the data source and data member. */
PropertyDescriptorCollection pcol = this
.BindingContext
[myDataSet, "Customers.custToOrders"].GetItemProperties();
/* Create a formatted column using a PropertyDescriptor.
The formatting character "c" specifies a currency format. */

DataGridColumnStyle csOrderAmount =
new
DataGridTextBoxColumn(pcol
["OrderAmount"], "c",
true
);
csOrderAmount.MappingName = "OrderAmount";
csOrderAmount.HeaderText = "Total";
csOrderAmount.Width = 100;
ts2.GridColumnStyles.Add(csOrderAmount);
/* Add the DataGridTableStyle instances to
the GridTableStylesCollection. */
myDataGrid.TableStyles.Add(ts1);
myDataGrid.TableStyles.Add(ts2);
// Sets the TablesAlreadyAdded to true so this doesn't happen again.
TablesAlreadyAdded=true
;
}
protected void button2_Click(object
sender, System.EventArgs e)
{
BindingManagerBase bmGrid;
bmGrid = BindingContext[myDataSet, "Customers"];
MessageBox.Show("Current BindingManager Position: " +
bmGrid.Position);
}
private void Grid_MouseUp(object
sender, MouseEventArgs e)
{
// Create a HitTestInfo object using the HitTest method.
// Get the DataGrid by casting sender.
DataGrid myGrid = (DataGrid)sender;
DataGrid.HitTestInfo myHitInfo = myGrid.HitTest(e.X, e.Y);
Console.WriteLine(myHitInfo);
Console.WriteLine(myHitInfo.Type);
Console.WriteLine(myHitInfo.Row);
Console.WriteLine(myHitInfo.Column);
}
// Create a DataSet with two tables and populate it.
private void
MakeDataSet()
{
// Create a DataSet.
myDataSet = new
DataSet("myDataSet");
// Create two DataTables.
DataTable tCust = new
DataTable("Customers");
DataTable tOrders =
new DataTable("Orders");
// Create two columns, and add them to the
first table.
DataColumn cCustID = new DataColumn("CustID", typeof(int
));
DataColumn cCustName =
new
DataColumn("CustName");
DataColumn cCurrent =
new DataColumn("Current", typeof(bool
));
tCust.Columns.Add(cCustID);
tCust.Columns.Add(cCustName);
tCust.Columns.Add(cCurrent);
// Create three columns, and add them to the second table.
DataColumn cID = new DataColumn("CustID", typeof(int
));
DataColumn cOrderDate =
new DataColumn("orderDate",typeof
(DateTime));
DataColumn cOrderAmount =
new DataColumn("OrderAmount", typeof(decimal
));
tOrders.Columns.Add(cOrderAmount);
tOrders.Columns.Add(cID);
tOrders.Columns.Add(cOrderDate);
// Add the tables to the DataSet.
myDataSet.Tables.Add(tCust);
myDataSet.Tables.Add(tOrders);
// Create a DataRelation, and add it to the DataSet.
DataRelation dr = new
DataRelation
("custToOrders", cCustID , cID);
myDataSet.Relations.Add(dr);
/* Populates the tables. For each customer and order,
creates two DataRow variables. */
DataRow newRow1;
DataRow newRow2;
// Create three customers in the Customers Table.
for(int
i = 1; i < 4; i++)
{
newRow1 = tCust.NewRow();
newRow1["custID"] = i;
// Add the row to the Customers table.
tCust.Rows.Add(newRow1);
}
// Give each customer a distinct name.
tCust.Rows[0]["custName"] = "Alpha";
tCust.Rows[1]["custName"] = "Beta";
tCust.Rows[2]["custName"] = "Omega";
// Give the Current column a value.
tCust.Rows[0]["Current"] = true
;
tCust.Rows[1]["Current"] =
true
;
tCust.Rows[2]["Current"] =
false
;
// For each customer, create five rows in the Orders table.
for(int
i = 1; i < 4; i++)
{
for(int
j = 1; j < 6; j++)
{
newRow2 = tOrders.NewRow();
newRow2["CustID"]= i;
newRow2["orderDate"]=
new
DateTime(2001, i, j * 2);
newRow2["OrderAmount"] = i * 10 + j * .1;
// Add the row to the Orders table.
tOrders.Rows.Add(newRow2);
}
}
}
}
 
Editing with DataGridTextBox and DataGridTextColumn

The DataGridTextBox and the DataGridTextBoxColumn work together to allow users to directly edit values in a DataGrid control column. The DataGridTextBoxColumn derives from DataGridColumnStyle, and is designed to host the DataGridTextBox, which derives from the TextBox control. In addition to the properties, events, and methods of the base control, you can call the KeyPress and KeyDown events with the OnKeyPress and OnMouseDown methods.


private
void GetDataGridTextBox()
{
// Gets the DataGridTextBoxColumn from the DataGrid control.
DataGridTextBoxColumn
myTextBoxColumn;
// Assumes the CompanyName column is a DataGridTextBoxColumn.
myTextBoxColumn = (DataGridTextBoxColumn)dataGrid1.
TableStyles[0].GridColumnStyles["CompanyName"];
// Gets the DataGridTextBox for the column.
DataGridTextBox myGridTextBox;
myGridTextBox = (DataGridTextBox) myTextBoxColumn.TextBox;
}

The DataGridTextBoxColumn class derives from the abstract (MustInherit in Visual Basic) class DataGridColumnStyle. At run time, the DataGridTextBoxColumn hosts a DataGridTextBox control that allows users to edit text. Special properties added to the class include Format, and HideEditBox. These properties allow you to access the hosted DataGridTextBox control and its attributes, and set the format for displaying values.


If the data source is a DataTable containing DataColumn objects, the DataType property of the DataColumn should be set to a data type that can logically be edited in a text box control. The following data types are automatically associated with a DataGridTextBoxColumn: Byte, DateTime, Decimal, Double, Int16, Int32, Int64, UInt16, UInt32, UInt64, Single, and String.


private
void AddColumn()
{
DataTable myTable=
new
DataTable();
// Add a new DataColumn to the DataTable.
DataColumn myColumn = new
DataColumn("myTextBoxColumn");
myColumn.DataType = System.Type.GetType("System.String");
myColumn.DefaultValue="default string";
myTable.Columns.Add(myColumn);
// Get the CurrencyManager for the DataTable.
CurrencyManager cm = (CurrencyManager)this
.BindingContext[myTable];
// Use the CurrencyManager to get the PropertyDescriptor for the
// new column.
PropertyDescriptor pd = cm.GetItemProperties()["myTextBoxColumn"];
DataGridTextBoxColumn myColumnTextColumn;
// Create the DataGridTextBoxColumn with the PropertyDescriptor.
myColumnTextColumn = new
DataGridTextBoxColumn(pd);
// Add the new DataGridColumn to the GridColumnsCollection.
dataGrid1.DataSource= myTable;
dataGrid1.TableStyles.Add(
new
DataGridTableStyle());
dataGrid1.TableStyles[0].GridColumnStyles.Add(myColumnTextColumn);
}


continue article

COMMENT USING