Implementing cascading DropDownList binding in a templated control
Asked Answered
S

4

5

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.

Sinus answered 19/7, 2011 at 15:38 Comment(0)
C
8

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;
 }
Crest answered 19/7, 2011 at 15:53 Comment(3)
OK so....then I would need to handle FormView.ItemInserting and add the parameter in manually? What about the same issue in Edit mode? Handle both the initial and updated values manually? Example code for posterity would be appreciated.Sinus
I verified this solution works. Thanks! I had some ideas similar to this but was not sure how most people approach the problem.Sinus
I am using this approach from many years, since I have started using this, I have search a lot from internet and could not find the solution other than I have provided to you.Crest
A
4

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>

Announce answered 17/7, 2012 at 12:46 Comment(2)
Can you give the full page source? This problem only occurs when you have cascading controls within a template, and my understanding is that DataBinder.Eval is essentially the same thing as just Eval.Sinus
@Sinus I thought they do the same thing. However, recently I found out that they are slightly different in the case of cascading drop down lists. I have attached my code and it is working perefectly.Announce
L
2

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

Leandro answered 1/3, 2012 at 13:54 Comment(0)
F
1

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>
Forefront answered 13/9, 2012 at 18:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.