The GridView, and indeed all the other templated data bound controls, are lifeblood to an ASP.NET developer when it comes to creating websites. A little DataSource control here, a GridView there and even if it isn’t exactly what you want, you’ve got a prototype page up and running in no time to start the real development with. Today’s chores involved tweaking the contents of a GridView’s EditItemTemplate so that the contents of one DropDownList (Clients) would change based on the contents of another (Roles) and should the Update button be clicked the values of both DropDownLists saved out to the database.

EditItemTemplate_2

The roles DropDownList always contained the same items, so it was bound to a DataSource control separate to the GridView itself and then its selected value bound to the current value for the row in the GridView. The RoleId is two-way bound to the SelectedValue of the DropDownList so clicking Update works correctly.

<EditItemTemplate>
   <asp:DropDownList runat="server" ID="ddlRolesForEditUserDialog" AutoPostBack="true"
      DataTextField="Name" DataValueField="RoleId" 
      DataSourceID="RolesDataSource" SelectedValue='<%# Bind("RoleId") %>'
      OnSelectedIndexChanged="ddlRolesForEditUserDialog_SelectedIndexChanged" />
</EditItemTemplate>

The clients DropDownList on the other hand, needed

  1. to be populated dynamically when the the GridView’s row was switched to Edit mode
  2. to be populated dynamically when the choice in the roles List changed.
  3. to be accessed when Update is clicked and the DataSource is making changes to the database.

As it turns out, each occasion used a slightly different way to find the row being edited and through that, using FindControl to access the ClientList.

In case 1, by the time a GridView’s OnRowEditing event (raised when ‘Edit’ is clicked on the GridView) is handled, the EditItemTemplate for the row hasn’t become accessible yet, so the client list can’t be found. The option instead then is to handle the GridView’s OnRowDataBound event at which point the EditItemTemplate has been created and the client list is accessible. The trick is to identify the row being edited is to use its RowState property. Every row on a GridView is rebound when Edit is clicked, so we can use the following.

protected void grdUsers_RowDataBound(object sender, GridViewRowEventArgs e)
{
   if ((e.Row.RowState == DataControlRowState.Edit) || 
       (e.Row.RowState == (DataControlRowState.Edit|DataControlRowState.Alternate)))
   {
      //Get the client dropdownlist
      DropDownList clientList = (DropDownList)e.Row.FindControl("ddlClients");

      //more stuff here
   }
}

In case 2, the EditItemTemplate already exists. Indeed, we’re capturing an event on the roles List within a cell in the EditItemTemplate. One option to then find the client List in the cell next to it is to start with the object that raised the event, find the control that contains both it and the client List and then call FindControl.

protected void RulesList_SelectedIndexChanged(object sender, EventArgs e)
{
   //Get the roles dropdownlist
   DropDownList ddlRoles = (DropDownList)sender;

   //Get the client dropdownlist
   DropDownList clientList = 
      (DropDownList)ddlRoles.Parent.Parent.FindControl("ddlClients");

   // more stuff here
}

Or, as in Case 3, because we know the EditItemTemplate is visible, we can locate the row being edited through the GridView’s EditIndex template. This returns -1 if no row is being edited or the index of a row in the GridView.

protected void usersDataSource_Updating(object sender, EventArgs e)
{
   GridViewRow row = grdUsers.Rows[grdUsers.EditIndex];
   DropDownList clientList = (DropDownList)row.FindControl("ddlClients");

   // more stuff here

}

Case 3 is the easiest way to find the currently edited row, though the other two are no less valid.