To read the article online, visit http://www.4GuysFromRolla.com/articles/051904-1.2.aspx

An Extensive Examination of the DataGrid Web Control: Part 16, Part 2

By Scott Mitchell


  • Read Part 1 of this Article

  • 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:

      <asp:TemplateColumn HeaderText="Division">
        <ItemTemplate>
          <%# DataBinder.Eval(Container.DataItem, "DivName") %>
        </ItemTemplate>
        <EditItemTemplate>
          <asp:DropDownList runat="server" id="ddlDivision" AutoPostBack="True"
                  OnSelectedIndexChanged="ddlDivision_SelectedIndexChanged"
                  DataTextField="Name" DataValueField="DivisionID" />
        </EditItemTemplate>
      </asp:TemplateColumn>
      <asp:TemplateColumn HeaderText="Division">
        <ItemTemplate>
          <%# DataBinder.Eval(Container.DataItem, "DeptName") %>
        </ItemTemplate>
        <EditItemTemplate>
          <asp:DropDownList runat="server" id="ddlDepartment"
                   DataTextField="Name" DataValueField="DepartmentID" />
        </EditItemTemplate>
      </asp:TemplateColumn>
    

    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:

    1. 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.
    2. 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);

          ddlDivision.DataSource = myCommand.ExecuteReader();
          ddlDivision.DataBind();

          myConnection.Close();

          // 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;

          DropDownList ddlDepartment = (DropDownList) e.Item.FindControl("ddlDepartment");

          PopulateDepartmentBasedOnDivision(ddlDepartment, ddlDivision, currentDepartmentID);
       }
    }


    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));

       ddlDepartment.DataSource = myCommand.ExecuteReader();
       ddlDepartment.DataBind();

       myConnection.Close();

       // 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");

       PopulateDepartmentBasedOnDivision(ddlDepartment, ddlDivision, -1);
    }

    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.

    Happy Programming!

  • By Scott Mitchell


    Attachments


  • Download the complete source code (in ZIP format)
  • Article Information
    Article Title: ASP.NET.An Extensive Examination of the DataGrid Web Control: Part 16, Part 2
    Article Author: Scott Mitchell
    Published Date: May 19, 2004
    Article URL: http://www.4GuysFromRolla.com/articles/051904-1.2.aspx


    Copyright 2017 QuinStreet Inc. All Rights Reserved.
    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers