views:

106

answers:

2

Hello! I use DetailsView to insert rows in database. Row has fields id, subcategory_id etc. I want to fill dynamically dropdownlist ddl_subcategories, which is used in TemplateField. Selected item value of first dropdownlist ddl_categories is used as parameter for generating collection for ddl_subcategories. I try it with using UpdatePanel, but method DataBind returns error "Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control.".

There's code of web form

<asp:DetailsView ID="dvw" runat="server" Height="50px" Width="125px" 
    AutoGenerateRows="False" DataSourceID="ods"
    DefaultMode="Insert" DataKeyNames="Section_id"
    OnDataBound="dvw_DataBound" OnItemUpdated="dvw_ItemUpdated" 
    OnItemCommand="dvw_ItemCommand">
    <Fields>
    <asp:TemplateField HeaderText="Category" >
       <ItemTemplate>
                 <asp:DropDownList ID="ddl_categories" runat="server" AutoPostBack="true" DataSourceID="ods_categories"
                  DataTextField="Name" DataValueField="Category_id" OnSelectedIndexChanged="category_select_index_changed"/>
       </ItemTemplate>
    </asp:TemplateField>            

    <asp:TemplateField HeaderText="Subcategory" >
        <ItemTemplate>
            <asp:UpdatePanel runat="server" UpdateMode="Conditional">
                <ContentTemplate>
                    <asp:DropDownList ID="ddl_subcategories" runat="server"                               
                          SelectedValue='<%# Bind("Subcategory_id") %>' />
                </ContentTemplate>
                <Triggers>
                    <asp:AsyncPostBackTrigger ControlID="ddl_categories" EventName="SelectedIndexChanged" />
                </Triggers>
            </asp:UpdatePanel>
        </ItemTemplate>
    </asp:TemplateField>
...
 </Fields>
</asp:DetailsView>

There is part of behind-code:

protected void category_select_index_changed(object sender, EventArgs e)
{
    DropDownList ddl_categories = (DropDownList)dvw.FindControl("ddl_categories");
    List<SUBCATEGORY> sections =  SUBCATEGORY.Select_all_by_parameters(Int32.Parse(ddl_categories.SelectedValue));//Select all subcategories by id of category
    DropDownList ddl_subcategories= (DropDownList)dvw.FindControl("ddl_subcategories");

    ddl_subcategories.DataSource = sections;
    ddl_subcategories.DataTextField = "Name";
    ddl_subcategories.DataValueField = "Subcategory_id";
    ddl_subcategories.DataBind();
}

What is my error? Thanks.

A: 

Hey,

Try wrapping the entire DetailsView with the update panel to see if that makes a difference...

HTH.

Brian
+1  A: 

The problem is that when you are data binding the subcategories dropdown, there is no DataBinding Context (see here for more info, pay attention to David Fowler's comments). I don't think the UpdatePanel is the issue as the behavior is the same with or without it (and if you wrap the entire DetailsView in an UpdatePanel).

A solution is to load the items individually instead of data binding the control. It seems a little clumsy, I admit, but it does work.

protected void category_select_index_changed(object sender, EventArgs e)
{
    DropDownList ddl_categories = (DropDownList)dvw.FindControl("ddl_categories");
    IEnumerable<SUBCATEGORY> sections = new SUBCATEGORY[] { new SUBCATEGORY() { Name = "First " + ddl_categories.SelectedValue, Subcategory_id = "1" }, new SUBCATEGORY() { Name = "Second", Subcategory_id = "2" } };
    DropDownList ddl_subcategories = (DropDownList)dvw.FindControl("ddl_subcategories");

    ddl_subcategories.Items.Clear();
    foreach (SUBCATEGORY cat in sections)
    {
        ddl_subcategories.Items.Add(new ListItem(cat.Name, cat.Subcategory_id));
    }
}

A better option would be to not use Bind in the control, and just set the value in the ObjectDataSource's parameters on Insert/Update.

Update: You can set the ObjectDataSource value directly. Add an event handler for the OnInserting (or OnUpdating as needed) as follows:

protected void ods_OnInserting(object sender, ObjectDataSourceMethodEventArgs e)
{
    DropDownList ddl_subcategories = (DropDownList)dvw.FindControl("ddl_subcategories");
    e.InputParameters["Subcategory_id"] = ddl_subcategories.SelectedValue;
}

I can't actually test this right now, but it should be close.

sgriffinusa
I tried that way. Fields of dropdownlist were filled up correctly. But form sent null-value from dropdownlist. What is reason?One more question. Is any way to set value in the ObjectDataSource programmatically?
greatromul
If I don't use update panel, ddl_subcategories returns correct value. But if I don't use update panel, I won't able to realize behaviour of controls without postback.
greatromul
If I use pure AJAX (web services and js) without update panel, it works. But it's interesting why it doesn't work with update panel.
greatromul
The reason that the first way is not returning values is because the data is not being filled at the correct time in the page lifecycle (http://john-sheehan.com/blog/net-cheat-sheet-aspnet-page-life-cycle-common-events/). I don't know why the update panel causes the problem, it doesn't work with or without the update panel in my tests. I updated my answer with details of how to set the ObjectDataSource value programmatically on insert/update.
sgriffinusa
Ok, thanks. I decided to use pure AJAX. I'll prepare new question. I found strange error in using 0-value in dropdownlist. Here is my new post http://stackoverflow.com/questions/3442019/formatexception-in-detailsview-which-uses-dynamically-inserted-value-for-item-of
greatromul