In response to the post about using casccading (dependent) drop-down lists, a number of people have wondered how you can use similar drop-downs in Insert mode in a FormView control. (Insert mode isn't supported in GridView controls.)
The technique is quite similar to how you use them in Update mode. As with Update mode, in the templates for the FormView control, you have a master and a dependent DropDownList control, each bound separately to a data source control that's inside the template. (The FormView control itself is bound to a data source control that includes Select, Update, and Insert queries for the actual data record.) The data source control for the master DropDownList runs an un-parameterized Select query. The data source control for the dependent DropDownList control runs a query that depends on the current value of the master list.
As with Update mode, the dependent list must establish the parameter value at run time, but you cannot do this entirely programmatically declaratively. So you need code for the same situations:- In the FormView control's DataBound event, which reads the current value of the master list and passes it to the query for the dependent list.
- In the SelectedIndexChanged event of the master list, to update the contents of the dependent list when a new selection is made in the master list.
- In the FormView control's ItemInserting event, to read the current value of the dependent list and set parameters that will be passed to the Insert query.
Because this is so similar to how you manage the DropDownList controls in Update mode, the code for the insert scenario is very similar, and in fact you can share code for both update and insert modes.
Of course, you also have to create the InsertItemTemplate in the FormView control and create a button/link to be able to switch to it. Again, quite similar to what's done for Update mode. I won't show you the InsertItemTemplate (it's boringly the same as the EditItemTemplate, but here's the big change, haha, for enabling Insert mode:<ItemTemplate>
<!-- rest of template here -->
<asp:LinkButton ID="Edit" runat="server"
CommandName="Edit">Edit</asp:LinkButton>
<asp:LinkButton ID="New" runat="server"
CommandName="New">New</asp:LinkButton>
</ItemTemplate>
And the data source control for the FormView control with its new Insert query (wrapped for clarity here!):<asp:AccessDataSource ID="CustomersDataSource"
runat="server"
DataFile="~/App_Data/cars.mdb"
SelectCommand="SELECT [CustomerID], [Name], [Manufacturer],
[Model] FROM [Customers]"
UpdateCommand="UPDATE [Customers] SET [Name] = ?, [Manufacturer] = ?,
[Model] = ? WHERE [CustomerID] = ?"
InsertCommand="Insert Into [Customers] ([Name], [Manufacturer], [Model])
Values (?, ?, ?)">
<UpdateParameters>
<asp:Parameter Name="Name" Type="String" />
<asp:Parameter Name="Manufacturer" Type="String" />
<asp:Parameter Name="Model" Type="String" />
<asp:Parameter Name="CustomerID" Type="Int32" />
</UpdateParameters>
<InsertParameters>
<asp:Parameter Name="Name" Type="String" />
<asp:Parameter Name="Manufacturer" Type="String" />
<asp:Parameter Name="Model" Type="String" />
</InsertParameters>
</asp:AccessDataSource>
I'll show you here the small differences in code as well. There's a working page here and a source listing here. (At the moment, the links on the sample page to the source listing and explanation are wrong! I'll fix those later. Fixed.)
There is really only one even slightly tricky thing here ... when you switch to Insert mode, all the controls are blank. Per our code, the master drop-down list is populated, but there's no existing data value for the manufacturer value. (Because there's no data at all -- it's a new blank record.) So there's is no master value that can be passed to query for the dependent data. What I did for this scenario was to reuse the code that is used when a selection is made in the master list. That logic extracts a parameter not from the current data record, but from whatever is selected in the master list. (Does that make sense? Hope so.)
The code for this scenario requires updates to the DataBound event; because I wanted to do the same thing I did when an item in the master list is selected, I refactored the code slightly. Here's the whole thing, changes in bold:Protected Sub FormView1_DataBound(ByVal sender As Object, _
ByVal e As System.EventArgs)
If FormView1.CurrentMode = FormViewMode.Edit Then
Dim dv As System.Data.DataRowView = FormView1.DataItem
listModels = FormView1.FindControl("listModels")
dataSourceModels = FormView1.FindControl("ModelsDataSource")
Dim m As String = dv("Manufacturer")
dataSourceModels.SelectParameters("Manufacturer").DefaultValue = m
listModels.DataBind()
If Not IsDBNull(dv("model")) Then
listModels.SelectedValue = dv("Model")
End If
End If
If FormView1.CurrentMode = FormViewMode.Insert Then
' Need to pre-populate the listModels control when
' the FormView control is switched into Insert mode.
' The listManufacturers list is populated automatically
' by the data source control, but the dependent
' dropdown is not.
PopulateDependentDropDown()
End If
End Sub
Protected Sub listManufacturers_SelectedIndexChanged(ByVal sender _
As Object, ByVal e As System.EventArgs)
PopulateDependentDropDown()
End Sub
Protected Sub PopulateDependentDropDown()
dataSourceModels = FormView1.FindControl("ModelsDataSource")
listManufacturers = FormView1.FindControl("listManufacturers")
listModels = FormView1.FindControl("listModels")
dataSourceModels.SelectParameters(0).DefaultValue = _
listManufacturers.SelectedValue
listModels.DataBind()
End Sub
Anyway, I hope this is useful.
Update 4 June I fixed a bunch of text (not code) in this entry that was confusing, incomplete, or wrong. Moral: Don't try to write blog entries when you're tired. Should be better now, altho I'm always open to suggestions for clarification.