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


March 14, 2007  |  Cascading DropDownLists in GridView -- Part 2  |  7396 hit(s)

Sorry for the interruption. I'll finish describing the details of having cascading DropDownList controls in edit mode of a GridView control. (Part 1 here.) I'll follow up in another post with some additional thoughts about the overall approach I've been illustrating.

The next task is to refresh the dependent drop-down list when the user makes a new selection in the master list. The master list control has AutoPostBack set to true; the refresh happens on SelectedIndexChanged:
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(sender, 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
(Gad, I really do wish it were easier to split lines in VB.)

(Update 13 Apr 2007 I changed the line that gets a reference to the listManufacturers drop-down list --
Dyaneshwar pointed out that I don't need to use FindControl, because it's already passed as the sender argument of the method.)

The code is similar to the code for populating the lists originally, and probably could be refactored so that you reuse the same code.

Finally, the update. When the user clicks the Update button, we need to set the parameter values that will be passed to the data source control that performs the actual update. We can do this during the GridView control's RowUpdating event by setting values in the NewValues dictionary of the System.Web.UI.WebControls.GridViewUpdateEventArgs object:
Protected Sub GridView1_RowUpdating(ByVal sender As Object, ByVal e _
As System.Web.UI.WebControls.GridViewUpdateEventArgs)
Dim listManufacturers As DropDownList = _
CType(GridView1.Rows(e.RowIndex).FindControl("listManufacturers"), _
DropDownList)
Dim listModels As DropDownList = _
CType(GridView1.Rows(e.RowIndex).FindControl("listModels"), _
DropDownList)
e.NewValues("ManufacturerID") = listManufacturers.SelectedValue
e.NewValues("ModelID") = listModels.SelectedValue
End Sub
The differences from the FormView version have primarily to do with the fact that the GridView control is showing multiple rows; in the FormView control, you're looking at one row at a time. For example, in the SelectedIndexChanged handler, we have to grub around -- that is, use GridView1.EditIndex -- to determine what row to turn our attentions to. We have to do essentially the same in the RowUpdating handler.

The grid itself is bound to a kind of complicated query (in the dsCarsForSale data source control). In this particular iteration of the example, I created the Cars.mdb as an uber-normalized set of tables. In the ItemTemplate (ie, normal display mode) of the grid, I want to display manufacturer name and model name. That required some inner joining. But that doesn't affect the updates, which care only about the various IDs.

I've posted an example page here, and the approximate source for it here, so you don't have to try to reconstruct it all from the examples above.

Like I said, I'll post a couple of further thoughts about this whole discussion of cascading lists in the future.




xiaobing   19 Mar 07 - 1:17 AM

Hi Mike,

I've tried do it in c#, it appear error:
Cannot implicitly convert type 'object' to 'System.Data.DataRowView'. An explicit conversion exists (are you missing a cast?)



protected void ProjectListGridView_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if (e.Row.RowState == DataControlRowState.Edit)
{
System.Data.DataRowView dv = e.Row.DataItem;

//Preselect correct value in PhaseEditDropDown
DropDownList PhaseEditDropDown = (DropDownList)(e.Row.FindControl("PhaseEditDropDown"));
PhaseEditDropDown.SelectedValue = (string)(dv["PhaseEditDropDown"]);

//Databind list of taskCode in dependent drop-down list, preselect value
DropDownList TaskEditDropDown = (DropDownList)(e.Row.FindControl("TaskEditDropDown"));
SqlDataSource dsc = (SqlDataSource)(e.Row.FindControl("SqlDataSourceEditTask"));
dsc.SelectParameters["PhaseName"].DefaultValue = (string)(dv["PhaseName"]);
TaskEditDropDown.DataBind();
TaskEditDropDown.SelectedValue = (string)(dv["TaskCode"]);
}
}




can you advise me?
Since I've tried again and again to create cascading ddl in Gridview edit template but failed again and again..

Thanks:)

Cheers*
xiaobing


 
mike   19 Mar 07 - 8:06 AM

It looks like e.Item.DataItem is just typed as object. Casting it worked for me:
System.Data.DataRowView dv = (System.Data.DataRowView)e.Row.DataItem;


 
Anonymous   20 Mar 07 - 2:28 AM

Thanks Mike.
It arise another problem but I will try to solve it.


Cheers*
xiaobing


 
Jason   21 Mar 07 - 7:45 PM

Mike,
I am just getting started with the 2.0 GridView, and your blog has been a great start. I did find, though, that instead of explictly setting the new values in the RowsUpdating event, I could just bind the dropdown's SelectedValue in EditItemTemplate. Either way, I enjoy your blog and it has been very helpful. Thanks.


 
mike   21 Mar 07 - 8:19 PM

Jason, can you post a little sample of the markup for your EditItemTemplate so that others can see how you've done the binding?

 
Jason   21 Mar 07 - 8:32 PM

Sure. Using your example, the listModels drop down declaration would look like this (please excuse the formatting):
<EditItemTemplate>
<asp:DropDownList ID="listModels" runat="server"
DataSourceID="dsModelsByManufacturer"
DataTextField="ModelName"
DataValueField="ModelID"
SelectedValue='<%# Bind("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>


 
John Bailo   26 Mar 07 - 3:20 PM

Fantastic article -- very concise and clear and easy to translate to other applications.

Not too much -- not too little -- just right!


 
Jason   09 Apr 07 - 11:36 AM

Mike, concerning my ealier post, the binding on the selectedvalue of the dropdown in the grid only works if you do not have dependant dropdowns. I was easing my way into your example, starting with one dropdown first. If a dropdown in the edit template does not depend on other edit template input, you can bind in the aspx. If it is dependant on another dropdown value, then you have follow the code example you previously posted. Either way, this has been a terrific example of how to do something fairly complicated ina clear, concise way. Thanks again.


 
Hoa Le   29 May 07 - 3:01 AM

Hi Mike,
Your blog on dependent dropdown list in grid view is very helpful.
I tried to adapt your technique on my assignment and it almost worked. The problem is I use an object data source (instead of inline sql as in your code) and when I click the edit button, I got the error : "Procedure 'sp_getModels' expects parameter '@ManufacturerId', which was not supplied."

Looks like this condition never is never met and therefore the parameter never passed:
if (e.Row.RowState == DataControlRowState.Edit)

Thanks much for your advice.
Hoa Le
Hoa


 
Sid   13 Aug 07 - 7:47 AM

Mike,

Thanks for posting this article. I've recently started using .net 2.0 and was struggling quite a bit with cascading dropdrown lists.

Using your example I tried something similar where I'm using ObjectDataSource to bind both my dropdownlists, but I'm facing a problem with it. The problem is that as the row is updated, no parameter is passed from the 2 dropdownlists.

So, using Visual Source Safe I updated code to select parent dropdown value using SelectedValue='<%# Bind("ManufacturerID")%>'. After this, ManufacturerID is passed as updateparameter, but there is no way that ModelID can be passed.

Please advice as to how one can overcome this problem? I'm sure I'm missing something, as no one else has posted anything about it.


 
Anonymous   07 Jan 08 - 11:13 PM

My datagrid breaks in the RowDataBound event when I use paging.

The errors occur when setting the SelectedValue & DefaultValue for SelectParameters.

I'm kind of a beginner in ASP.NET 2.0 and tried to fix by guessing and adding a check like this one:

If e.Row.RowType = DataControlRowType.DataRow Then

but it didn't help.


 
Dean McCarthy   08 Apr 08 - 3:13 AM

Hi Mike

Just wanted to say a BIG thanks for taking the time to write this article.

I've been trying all sorts for the last three days to get cascading drop down lists to work in a Gridview Edit Tempale.

Your style was very easy to follow.

Cheers