In Part 1 of this article we looked at the data model and first steps necessary
for creating an editable DataGrid with two data-dependent DropDownLists. In this part we'll see how to create the
editable portion of the DataGrid, and how to automatically have the second DropDownList's options update based on the
selection of the first.
Creating the EditItemTemplate
The next step is to create the EditItemTemplate in the two TemplateColumn DataGrid columns. The EditItemTemplate, as
you know, contains the HTML and Web control markup that's rendered when a row is marked as edited (via the DataGrid's
EditItemIndex property) and the data rebound to the grid. We want the EditItemIndex to include a DropDownList
Web control:
As you can see, the EditItemTemplate contains a DropDownList for both TemplateColumns; both DropDownLists have their
DataTextField and DataValueField set to the appropriate fields in the respective tables.
The Division TemplateColumn,
however, has its AutoPostBack property set to True, along with its SelectedIndexChanged
event wired up to the ddlDivision_SelectedIndexChanged event handler (which we'll examine shortly).
The reason the Division TemplateColumn has these two additions is so that whenever the user modifies his selection
from the Division DropDownList, the Web page will be posted back and the ddlDivision_SelectedIndexChanged event handler
will fire. From this event handler, we'll populate the contents of the Department DropDownList based on the selected
Division.
Populating the DropDownLists
The final piece left in the puzzle is populating the two DropDownLists. There are two occasions where these lists
need to be populated:
When the DataGrid is being placed in edit mode. This involves setting the EditItemIndex to the
index of the row to be edited, and rebinding the data to the DataGrid. At this point, we need to populate the
two DropDownLists and set their selected value based on the database data.
When the end user selects a different division. At this point we must populate the Department DropDownList based
on the selected division.
To populate the DropDownLists when the DataGrid is being placed in edit mode, we'll create an event handler for the
DataGrid's ItemDataBound event. This event fires once for each row whenever the DataGrid's
DataBind method is called. What we'll do is check to see if the current row being bound is the editable
row. If so, we'll get a reference to the Division DropDownList and populate it with the rows from the Divisions
table. Following this, we'll select the correct division, based on the current employee's division ID.
Next, we'll get a reference to the Department DropDownList and populate it with the rows from the
Departments table based on the selected division. Lastly, we'll select the department based on the employee's
DepartmentID. The following code accomplishes this:
private void DataGrid1_ItemDataBound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
{
// see if we are working with the row being edited
if (e.Item.ItemType == ListItemType.EditItem)
{
// populate the division DDL
DropDownList ddlDivision = (DropDownList) e.Item.FindControl("ddlDivision");
// connect to Access DB
OleDbConnection myConnection = new OleDbConnection(ConfigurationSettings.AppSettings["connString"]);
myConnection.Open();
const string SQL = @"SELECT DivisionID, Name FROM Divisions ORDER BY Name";
OleDbCommand myCommand = new OleDbCommand(SQL, myConnection);
// now, select the appropriate division
int currentDivisionID = Convert.ToInt32(DataBinder.Eval(e.Item.DataItem, "DivisionID"));
ListItem li = ddlDivision.Items.FindByValue(currentDivisionID.ToString());
if (li != null) li.Selected = true;
// finally, populate the department DDL based on the selected division
int currentDepartmentID = Convert.ToInt32(DataBinder.Eval(e.Item.DataItem, "DepartmentID"));
if (li != null) li.Selected = true;
private void PopulateDepartmentBasedOnDivision(DropDownList ddlDepartment, DropDownList ddlDivision, int currentDepartmentID)
{
int divID = Convert.ToInt32(ddlDivision.SelectedValue);
// connect to Access DB
OleDbConnection myConnection = new OleDbConnection(ConfigurationSettings.AppSettings["connString"]);
myConnection.Open();
const string SQL = @"SELECT DepartmentID, Name FROM Departments WHERE DivisionID = @DivisionID ORDER BY Name";
OleDbCommand myCommand = new OleDbCommand(SQL, myConnection);
myCommand.Parameters.Add(new OleDbParameter("@DivisionID", divID));
// now, select the appropriate division
ListItem li = ddlDepartment.Items.FindByValue(currentDepartmentID.ToString());
if (li != null) li.Selected = true;
}
The DataGrid1_ItemDataBound event handler fires once for each item being bound to the DataGrid. If
the current item being bound is the editable item, then the DropDownLists are appropriately populated and
have their selected items set based on the employee's data. (e.Item.DataItem is a reference to the
data being bound to the DataGrid row that triggered the ItemDataBound event.)
The PopulateDepartmentBasedOnDivision() method is a helper method that populates the contents of
the Department DropDownList based on the currently selected Division DropDownList value. The reason I separated this
functionality into a separate method, rather than having it embedded in the DataGrid1_ItemDataBound event handler,
is so that its functionality can be reused when a user selects a different Division.
Recall that when a user selects a different Division, the Web Form is automatically posted back (since the Division
DropDownList's AutoPostBack property is set to True) and the ddlDivision_SelectedIndexChanged
event handler fires. From this event handler, all that we have to do is get a reference to the Division and Department
DropDownLists, and then call the PopulateDepartmentBasedOnDivision() method. The following code illustrates
how this is accomplished:
protected void ddlDivision_SelectedIndexChanged(object sender, EventArgs e)
{
// get a reference to the Department DDL for this row
DropDownList ddlDivision = (DropDownList) sender;
DataGridItem dgi = (DataGridItem) ddlDivision.Parent.Parent;
DropDownList ddlDepartment = (DropDownList) dgi.FindControl("ddlDepartment");
The thing to note here is that the ddlDivision_SelectedIndexChanged event handler receives a reference
to the DropDownList that triggered the event (sender). To get the associated Department DropDownList
for the Division DropDownList, I first accessed the DataGridItem that contains both DropDownLists.
Then I used FindControl() to reference the Department DropDownList. (Alternatively, I could have accessed
the DataGrid's Items collection based on the EditItemIndex.)
This wraps up the example! Admittedly, this article glossed over some of the more basic DataGrid features, such as
wiring up the ItemDataBound event to the DataGrid1_ItemDataBound event handler, and programmatically
referencing DropDownLists in the DataGrid's TemplateColumns, but these techniques are discussed elsewhere in this article
series, as well as on DataWebControls.com. The point of this article was to
illustrate how to create an editable DataGrid with two data-dependent DropDownLists.
While this article showed an editable DataGrid with two data-dependent DropDownLists, there's no reason why the technique
couldn't be extended to handle more than two DropDownLists. I have implemented solutions for clients with three and
more data-dependent DropDownLists using code very similar to what's presented here.
Finally, if you are interested in implementing an editable DataGrid with two or more data-dependent DropDownLists,
I encourage you to download the example code available at the end of this article.