Thursday, May 07, 2009

Cascading DropDownLists in DetailsView – Databinding error

I came across a requirement to have linked DropdownLists in insert mode of  DetailsView bound to EntityDataSource.

In insert mode of DetailsView one of the fields is bound to a dropdownlist’s selected value.  But the requirement here is values of dropdownlist vary depending on where condition bound to selected value of another dropdown list.

 image

As shown above TaskID is one of the fields. But tasks vary based on project selected. This is achieved by converting TaskField to TemplateField. I have pasted below code for EditTemplate, InsertTemplate and ItemTempalte. In this only TaskID is bound column while project is added manually.

Without doing modifications shown below I was getting error

Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control.

This is because upon postback DetailsView control is not re binding to selected value  SelectedValue='<%# Bind("TaskID") %>'

<asp:TemplateField HeaderText="TaskID" SortExpression="TaskID">

<
EditItemTemplate>
<
asp:Label ID="Label3" runat="server" Text='<%# Eval("TaskID") %>'></asp:Label>
</
EditItemTemplate>

<
InsertItemTemplate>
<
asp:DropDownList ID="DropDownList5" runat="server" AutoPostBack="True"
DataSourceID="EntityDataSource5" DataTextField="ProjectName"
DataValueField="ProjectID" Width="100%">
</
asp:DropDownList>
<
asp:EntityDataSource ID="EntityDataSource5" runat="server"
ConnectionString="name=MyEntities" include="Tasks"
DefaultContainerName="MyEntities" EntitySetName="Projects">
</asp:EntityDataSource>
<
br />
<
asp:DropDownList ID="DropDownList4" runat="server"
DataSourceID="EntityDataSource6" DataTextField="TaskDescription"
DataValueField="TaskID" Width="100%">
</
asp:DropDownList>
<
asp:EntityDataSource ID="EntityDataSource6" runat="server"
ConnectionString="name=MyEntities"
DefaultContainerName="MyEntities" EntitySetName="Tasks"
Where="it.ProjectID==@ProjectID" >
<
WhereParameters
>
<
asp:ControlParameter ControlID="DropDownList5" Name
="ProjectID"
Type="Int32" PropertyName
="SelectedValue" />
</
WhereParameters
>
</
asp:EntityDataSource>
</
InsertItemTemplate>

<
ItemTemplate>
<
asp:Label ID="Label3" runat="server" Text='<%# Bind("TaskID") %>'></asp:Label>
</
ItemTemplate>

</
asp:TemplateField>

Also observe highlighted portions where autopostback is set for project dropdownlist and its selectedvalue is bound to DetailsView in where condition of Tasks Dropdownlist. But here TaskID selected value is not bound to TaskID field of DetailsView.

This binding is made in OnItemInserting event handler of DetailsView as shown below

<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False" CellPadding="4"
DataKeyNames="ResourceID" DataSourceID="EntityDataSource2" ForeColor="#333333"
GridLines="None" Height="50px" Width="125px" OnItemInserted="DetailsView1_ItemInserted"
DefaultMode="Insert" OnItemInserting="DetailsView1_OnItemInserting">

with page behind file containing handler like

protected void DetailsView1_OnItemInserting(object sender, DetailsViewInsertEventArgs e)
{
String TaskID = ((DropDownList)(DetailsView1.FindControl("DropDownList4"))).SelectedValue;
e.Values.Add("TaskID", TaskID);
}

Here inserting event is handled to add TaskID field to values based on selected value of TaskID’s DropDownlist.

2 comments:

Anonymous said...

Thank you!!!
You saved my day, I was looking at this for hours, tried multiple methods until saw your post. Thank you!

Anonymous said...

Thank You - You are a God

So simple and elegant

Tim