Implementing cascading DropDownList binding in a templated control

I have 2 DropDownList controls on my form, the second of which uses the SelectedValue of the first as one of its binding parameters.

Both DropDownList controls are in a FormView.InsertItemTemplate with SelectedValue properties bound to the FormView‘s datasource using a Binding Expression.

The first time the FormView renders in Insert mode, everything works fine. The problem is after an AutoPostBack from the first DropDownList, the FormView doesn’t (re-)bind, however since the ControlParameter on the second DropDownList has changed, it DOES bind (as intended), but an exception occurs on the Binding Expression of the second DDL, I assume since the FormView is not binding on that pass:

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

Here is the markup:

<InsertItemTemplate>
.
.
.
<tr class="GridViewRowB">
                    <td class="GridViewCell">
                        Offense Type
                    </td>
                    <td class="GridViewCell">
                        <asp:DropDownList ID="ddlOffenseType" runat="server" DataSourceID="dsOffenseType"
                            AutoPostBack="true" DataValueField="OffenseTypeID" DataTextField="Description"
                            SelectedValue='<%# Bind("OffenseTypeID") %>'>
                        </asp:DropDownList>
                        <asp:ObjectDataSource ID="dsOffenseType" runat="server" TypeName="OffenseType"
                            SelectMethod="GetAll">
                            <SelectParameters>
                                <asp:Parameter Name="ActiveOnly" DefaultValue="True" Type="Boolean" />
                            </SelectParameters>
                        </asp:ObjectDataSource>
                    </td>
                </tr>
                <tr class="GridViewRowA">
                    <td class="GridViewCell">
                        Attorney
                    </td>
                    <td class="GridViewCell">
                        <asp:DropDownList ID="ddlAttorney" runat="server" DataSourceID="dsAttorney" DataValueField="AttorneyID"
                            DataTextField="AttorneyNameWithCount" SelectedValue='<%# Bind("AttorneyID") %>'>
                        </asp:DropDownList>
                        <asp:ObjectDataSource ID="dsAttorney" runat="server" TypeName="Attorney"
                            SelectMethod="GetAttorneyWithCaseCount">
                            <SelectParameters>
                                <asp:Parameter Name="ActiveOnly" DefaultValue="True" Type="Boolean" />
                                <asp:ControlParameter Name="OffenseTypeID" Type="Int32" ControlID="ddlOffenseType"
                                    PropertyName="SelectedValue" />
                            </SelectParameters>
                        </asp:ObjectDataSource>
                    </td>
                </tr>
.
.
.
</InsertItemTemplate>

My question is: What is the best way to make this functionality work? Is it possible to keep both DDL’s inside the template? I would prefer to avoid using the AJAX toolkit or other client-side solutions.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

This is an issue when we use cascading dropdownlist in Databinding Controls like DetailsView/FormView and I have faced it many times. You have to remove the Binding Expression from your Second Dropdownlist SelectedValue='<%# Bind("AttorneyID") %>', then it will work.

Secondly if you remove the Binding expression, you have to pass the value manually in FormView ItemInserting Event. e.g.

 protected void frmAsset_ItemInserting(object sender, FormViewInsertEventArgs e)
 {
    eValues["AttorneyID"] = ((DropDownList)((FormView)sender).FindControl("ddlAttorny")).SelectedValue;
 }

Method 2

Actually I’m posting this answer in case anybody else got stuck like I did.
What Muhammad Akhtar said works perfectly, however I found a simpler solution.
In

<asp:DropDownList ID="ddlAttorney" runat="server" DataSourceID="dsAttorney" DataValueField="AttorneyID" DataTextField="AttorneyNameWithCount" SelectedValue='<%# Bind("AttorneyID") %>'>

change Bind("AttorneyID") to DataBinder.Eval (Container.DataItem, "AttorneyID")
It works perfectly!
EDIT: My sample code:

<asp:Content ID="Content3" ContentPlaceHolderID="BodyContent" runat="Server">
<asp:DetailsView ID="dv" runat="server" Height="50px" DataSourceID="ODS" DefaultMode="Insert"
    AutoGenerateRows="False" OnItemCommand="dv_ItemCommand" OnItemInserted="dv_ItemInserted"
    DataKeyNames="Id" OnItemUpdated="dv_ItemUpdated" CssClass="DetailsView" 
    >
    <Fields>
        <asp:TemplateField HeaderText="Page Name:">
            <ItemTemplate>
                <asp:Label ID="txtPageName" runat="server" Text="<%#Bind('PageName') %>" />
            </ItemTemplate>
            <EditItemTemplate>
                <asp:TextBox ID="txtPageName" runat="server" Text="<%#Bind('PageName') %>" />
            </EditItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Parent:">
            <ItemTemplate>
                <asp:Label ID="txtParentPageName" runat="server" Text='<%#Bind("ParentPageName") %>' />
            </ItemTemplate>
            <EditItemTemplate>
                <asp:DropDownList runat="server" ID="lstParentPage" DataSourceID="ParentPageODS"
                    AppendDataBoundItems="true" DataTextField="PageName" DataValueField="Id" SelectedValue="<%#Bind('ParentPage') %>"
                    AutoPostBack="True">
                    <asp:ListItem Text="-Root-" Value="" />
                </asp:DropDownList>
            </EditItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="After...">
            <ItemTemplate>
                <asp:Label ID="txtPreviousPage" runat="server" Text='<%#Bind("PageOrder") %>' />
            </ItemTemplate>
            <EditItemTemplate>
                <asp:DropDownList runat="server" ID="lstPageOrder" AppendDataBoundItems="true" DataTextField="PageName" DataSourceID="PageOrderODS" DataValueField="PageOrder"  EnableViewState="False" SelectedValue='<%# DataBinder.Eval (Container.DataItem, "PageOrder") %>'>
                    <asp:ListItem Text="-First-" Value="" />
                </asp:DropDownList>
                <asp:ObjectDataSource ID="PageOrderODS" runat="server" SelectMethod="SelectByParent"
                    TypeName="SirM2X.Pages">
                    <SelectParameters>
                        <asp:ControlParameter ControlID="lstParentPage" Name="ParentPage" PropertyName="SelectedValue" />
                    </SelectParameters>
                </asp:ObjectDataSource>
            </EditItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Dummy Page?">
            <ItemTemplate>
                <asp:Label runat="server" ID="txtDummyPage" Text="<%#Bind('IsDummyText') %>" />
            </ItemTemplate>
            <EditItemTemplate>
                <asp:CheckBox ID="chkIsDummy" runat="server" Checked="<%#Bind('IsDummy') %>" />
            </EditItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField ShowHeader="False">
            <EditItemTemplate>
                <asp:Button ID="btnUpdate" runat="server" CausesValidation="True" CommandName="Update"
                    Text="<%$Resources:Resources, Update %>" />
                &nbsp;<asp:Button ID="btnCancel" runat="server" CausesValidation="False" CommandName="Cancel"
                    Text="<%$Resources:Resources, Cancel %>" />
            </EditItemTemplate>
            <InsertItemTemplate>
                <asp:Button ID="btnInsert" runat="server" CausesValidation="True" CommandName="Insert"
                    Text="<%$Resources:Resources, Insert %>" />
                &nbsp;<asp:Button ID="btnCancel" runat="server" CausesValidation="False" CommandName="Cancel"
                    Text="<%$Resources:Resources, Cancel %>" />
            </InsertItemTemplate>
            <ItemTemplate>
                <asp:Button ID="btnEdit" runat="server" CausesValidation="False" CommandName="Edit"
                    Text="<%$Resources:Resources, Edit %>" />
            </ItemTemplate>
        </asp:TemplateField>
    </Fields>
</asp:DetailsView>
<asp:ObjectDataSource ID="ODS" runat="server" DeleteMethod="DeleteRow" InsertMethod="InsertRow"
    SelectMethod="SelectRow" TypeName="SirM2X.Pages" UpdateMethod="UpdateRow" OnInserting="ODS_Inserting"
    OnUpdating="ODS_Updating">
    <DeleteParameters>
        <asp:Parameter Name="Id" Type="Int32" />
    </DeleteParameters>
    <InsertParameters>
        <asp:Parameter Name="PageName" Type="String" />
        <asp:Parameter Name="CreatedBy" Type="String" />
        <asp:Parameter Name="ParentPage" Type="Int32" />
        <asp:Parameter Name="PageOrder" Type="Int32" />
        <asp:Parameter Name="IsDummy" Type="Boolean" />
    </InsertParameters>
    <SelectParameters>
        <asp:QueryStringParameter Name="Id" QueryStringField="ID" Type="Int32" />
    </SelectParameters>
    <UpdateParameters>
        <asp:Parameter Name="Id" Type="Int32" />
        <asp:Parameter Name="PageName" Type="String" />
        <asp:Parameter Name="ParentPage" Type="Int32" />
        <asp:Parameter Name="PageOrder" Type="Int32" />
        <asp:Parameter Name="IsDummy" Type="Boolean" />
        <asp:Parameter Name="DeleteState" Type="Boolean" />
    </UpdateParameters>
</asp:ObjectDataSource>
<asp:ObjectDataSource ID="ParentPageODS" runat="server" SelectMethod="SelectAll"
    TypeName="SirM2X.Pages"></asp:ObjectDataSource>

Method 3

This may come a little bit late but better late than never:

Protected Sub DetailsView1_ItemUpdating(sender As Object, e As System.Web.UI.WebControls.DetailsViewUpdateEventArgs) Handles DetailsView1.ItemUpdating
  e.NewValues("AtendeeSubType") = DirectCast(DirectCast(sender, DetailsView).FindControl("dropdownlist3"), DropDownList).SelectedValue
End Sub

I tested this for the event ItemUpdating of a details view but I think it will work for a formview, just switch the parts you need and it will work.

Edit: You can check this reference:
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.detailsview.itemupdating.aspx

Method 4

Here is how I did it…

<asp:SqlDataSource ID="sqldsDDPlant" runat="server" ConnectionString="<%$ ConnectionStrings:SeedTrackerConnectionString %>" 
    SelectCommand="SELECT * FROM [Plant] ORDER BY [Plant]"></asp:SqlDataSource>

<asp:SqlDataSource ID="sqldsDDType" runat="server" ConnectionString="<%$ ConnectionStrings:SeedTrackerConnectionString %>" 
    SelectCommand="SELECT * FROM [Type] ORDER BY [Type]" FilterExpression="PLID = '{0}'">
        <FilterParameters>
            <asp:ControlParameter Name="plantParam" ControlID="DVSeedTracker$ddPlant" PropertyName="SelectedValue" />
        </FilterParameters>  
</asp:SqlDataSource>

        <asp:TemplateField HeaderText="Plant">
            <InsertItemTemplate>
                <asp:DropDownList ID="ddPlant" runat="server" AutoPostBack="true" SelectedValue='<%# Bind("PLID") %>'
                 DataSourceID="sqldsDDPlant"  DataTextField="Plant" DataValueField="PLID" AppendDataBoundItems="True">
                    <asp:ListItem></asp:ListItem>
                </asp:DropDownList>
                 <asp:RequiredFieldValidator
                    id="RequiredFieldValidator2"
                    runat="server"
                    ControlToValidate="ddPlant"
                    Display="Static"
                    ErrorMessage="*Required" CssClass="RequiredField" />                
            </InsertItemTemplate>
        </asp:TemplateField>

        <asp:TemplateField HeaderText="Type">
            <InsertItemTemplate>
                <asp:DropDownList ID="ddType" runat="server"
                DataSourceID="sqldsDDType"  DataTextField="Type" DataValueField="TYPID" AppendDataBoundItems="False">
                    <asp:ListItem></asp:ListItem>
                </asp:DropDownList>
                    <asp:RequiredFieldValidator
                    id="RequiredFieldValidator3"
                    runat="server"
                    ControlToValidate="ddType"
                    Display="Static"
                    ErrorMessage="*Required" CssClass="RequiredField" />                                   
            </InsertItemTemplate>
        </asp:TemplateField>


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x