1. Original Entry + Comments2. Write a Comment3. Preview Comment
New comments for this entry are disabled.


March 13, 2007  |  Cascading Dropdowns -- GridView  |  17480 hit(s)

I've been messing with cascading drop-down lists in the FormView control. In a comment, someone asked if the same thing can be done in a GridView control in edit mode. Yes. The overall approach is pretty much the same. There are a few details that differ because we're in a GridView row.

To review, when you're working with cascading DropDownList controls, you need to perform these tasks:
  • Populate each of the DropDownList controls.
  • Pre-select the appropriate value in each list to match what's currently in the data.
  • When the user selects a new value in the master dropdown, repopulate the detail dropdown with a new set of dependent values.
  • When the row is saved, read the values from the dropdown lists and use them to set the values of parameters that will be passed to the database query that updates the database.
Update Some folks have requested info about the schema of the tables involved in this exercise. Here you go:
Customers
CustomerID
Name
Manufacturer
Model
Manufacturers
Manufacturers
Models
ModelID
Manufacturer
Model

As I say, you can do this in the GridView control in a way similar, but not identical, to how you do it in FormView. Let's say you have a grid that looks like this in normal mode (ItemTemplate):



And like this in edit mode (EditItemTemplate):



When you configure the GridView control, you have to convert the columns for Manufacturer and Model from BoundField columns (default) to TemplateField columns. A template column gives you a way to design the column contents freeform. Then you edit the columns. For the ItemTemplate of both columns, you add a Label control and data-bind it using the Bind (or even just the Eval) method. Here's an example of the Manufacturer column showing just the ItemTemplate element:
<asp:TemplateField HeaderText="Manufacturer" 
SortExpression="Manufacturer">
<ItemTemplate>
<asp:Label ID="Label1"
runat="server"
Text='<%# Bind("Manufacturer") %>'>
</asp:Label>
</ItemTemplate>


[...]
The EditItemTemplate is where the fun happens. As with the FormView example from before, the template contains both the drop-down list and the data source control for that list. Here's the markup for the EditItemTemplate element for the Manufacturer column:
<EditItemTemplate>
<asp:DropDownList
ID="listManufacturers"
runat="server"
DataSourceID="dsManufacturers"
DataTextField="Manufacturer"
DataValueField="ManufacturerID"
autopostback=true
OnSelectedIndexChanged="listManufacturers_SelectedIndexChanged">
</asp:DropDownList>


<asp:AccessDataSource ID="dsManufacturers"
runat="server"
DataFile="~/App_Data/Cars.mdb"
SelectCommand="SELECT [ManufacturerID], [Manufacturer] FROM [Manufacturers]">
</asp:AccessDataSource>
</EditItemTemplate>
Notice that the AutoPostBack property of the DropDownList control is true. As soon as users select an item from the list, we want to refresh the dependent drop-down list.

Here's the Model column (I wrapped the query for readability):
<asp:TemplateField HeaderText="Model" SortExpression="ModelName">
<ItemTemplate>
<asp:Label ID="Label2"
runat="server"
Text='<%# Bind("ModelName") %>'>
</asp:Label>
</ItemTemplate>


<EditItemTemplate>
<asp:DropDownList ID="listModels"
runat="server"
DataSourceID="dsModelsByManufacturer"
DataTextField="ModelName"
DataValueField="ModelID" />


<asp:AccessDataSource
ID="dsModelsByManufacturer"
runat="server"
DataFile="~/App_Data/Cars.mdb"
SelectCommand="SELECT [ModelID], [ModelName] FROM [Models] WHERE
([ManufacturerID] = ?)">
<SelectParameters>
<asp:Parameter Name="ManufacturerID" />
</SelectParameters>
</asp:AccessDataSource>


</EditItemTemplate>
</asp:TemplateField>
The Model column also contains a data source control. The query is parameterized; the ManufacturerID value will be supplied at run time.

And now some code. First, we want to populate the controls and preselect the current item. The right time to do that is when the GridView control is doing its data-binding thing.
Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e _
As System.Web.UI.WebControls.GridViewRowEventArgs)
If (e.Row.RowState And DataControlRowState.Edit) = _
DataControlRowState.Edit Then
Dim dv As System.Data.DataRowView = e.Row.DataItem

' Preselect correct value in Manufacturers list
Dim listManufacturers As DropDownList = _
e.Row.FindControl("listManufacturers")
listManufacturers.SelectedValue = dv("ManufacturerID")


' Databind list of models in dependent drop-down list
Dim listModels As DropDownList = _
e.Row.FindControl("listModels")
Dim dsc As AccessDataSource = _
e.Row.FindControl("dsModelsByManufacturer")
dsc.SelectParameters("ManufacturerID").DefaultValue = _
dv("ManufacturerID")
listModels.DataBind()
listModels.SelectedValue = dv("ModelID")
End If
End Sub
(Some ugly line-continuations in there, sorry.)

The drop-down lists are displayed only in edit mode, so the code first tests e.Row.RowState. That guy threw me for a while -- turns out that it's a bitfield, so you test it by ANDing it. Having established that edit mode is active, the code gets the current manufacturer ID from the current data item (typed as DataRowView) and selects that value. Then it uses the manufacturer ID to set the parameter value for the query in the model data source, binds the model drop-down list, and then preselects the current model.

Wow, this is getting long. To be continued ...

Update The next blog entry finishes this discussion and includes a link to the source code for this page.




Anonymous   05 Jul 07 - 6:21 AM

thank you! You were the only site I could find after three days of searching which identified how to get to the control in an edititemtemplate in the gridview. Simply through the databound event of the grid iteself.
Thanks again.


 
Andre.   22 Jan 08 - 3:50 AM

Well.. I did it... but actually in my case something really strange is happening..... When I edit the rowindex 1 is does not launch rowdatabound event.. Do you know why? All other rows the event is launched, just rowindex 1 not.

 
David   21 Oct 08 - 1:41 AM

Ever done this is the footer of a gridview?

 
Omar   18 Jan 09 - 9:15 AM

Can his example be posed with SQLinstaed of Access?

 
mike   18 Jan 09 - 9:17 AM

SQL instead of Access:

http://mikepope.com/blog/DisplayBlog.aspx?permalink=2056


 
Omar Jorel   19 Jan 09 - 3:04 PM

Can this be done with SQL instead of Access?

 
Omar Jorel   19 Jan 09 - 3:07 PM

Can this be done with SQL instead of Access?

I mean in Gridview instead of Formview with SQL?

You did a great program in Formview with SQL.


 
Anthony Howitt   16 Feb 09 - 11:19 AM

Thank you. I was getting in a right muddle with this until I found your solution. A possible small improvement: if you use FilterParameters it saves a few lines of code. Thanks again.

 
Michael   12 Jul 09 - 2:50 PM

Hi Mike,

Great article. I am having an issue though and I think I'm missing something. What code goes in the "listManufacturers_SelectedIndexChanged" event?


 
mike   12 Jul 09 - 6:56 PM

This is what I have in the event handler ... does this work for you?
    Protected Sub listManufacturers_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs)
Dim listManufacturers, listModels As DropDownList
Dim dsModelsByManufacturer As AccessDataSource
Dim currentRowInEdit As Integer = GridView1.EditIndex
listManufacturers = CType(GridView1.Rows(currentRowInEdit).FindControl("listManufacturers"), DropDownList)
listModels = CType(GridView1.Rows(currentRowInEdit).FindControl("listModels"), DropDownList)
dsModelsByManufacturer = CType(GridView1.Rows(currentRowInEdit).FindControl("dsModelsByManufacturer"), AccessDataSource)

dsModelsByManufacturer.SelectParameters("manufacturerID").DefaultValue = listManufacturers.SelectedValue
listModels.DataBind()
End Sub


 
Hossein Kord   14 Jul 09 - 12:28 PM

Thank you very much for an excellent post.
I have been stuck on this issue (Cascading Dropdown in Gridview Edit Mode) for the last 4 days and have tried many recommendations from different sites (both AJAX and ASP). Your post was the only one that finally saved the day.

Thank you again
Kord


 
Angela T   13 Jul 10 - 8:31 PM

Excellent article - have been struggling with this for a couple days, your article was easy to understand and worked exactly as described. Thank you!

 
Tony Dyer   30 Nov 10 - 8:37 AM

This is an excellent post, thabnks so much. I spent nearly 2 days trying to solve this - other offerings on the web are horribly dense and/or complex.

One very small point - you probably need to clear out the subsidiary DropDownList items before re-binding after changing the parent selection. I also add in a blank line (or some other 'nothing selected' indicator). (This may hav been set in the default list and AppendDataBoundItems set, but the items.clear seems to remove it ).


 
Anonymous   08 Aug 11 - 7:33 AM

+1 !!!

 
Anonymous   15 Nov 12 - 1:11 PM

Can you post the full page of source code for the gridview cascading dropdowns like you did for the formview cascading dropdowns?

 
mike   15 Nov 12 - 8:12 PM

There's a link to the source in the continuation of this entry:

http://www.mikepope.com/blog/Displayblog.aspx?permalink=1709

I'll update the text of this entry so that that's clear.