asp.netvb.netuser-controlsdatalistdynamic-controls

Dynamically added controls remove when dropdown event fired in the datalist in user control


I am working on an ASP.NET VB.NET web form - a reservation web application, in which only one aspx page and rest are user-control page.

At run-time of aspx page, user controls load as per step and name define in db, like in below link.

ASP.NET Custom user control to add dynamically

In the first step, the first user-control is bind in page-init which is used to shows reservation availability detail in .NET datalist control like (see images).

enter image description here

All the details are bind to generate run-time control via data-list's item_databound event.

  1. ImageOfRoom (asp.net Image Control) - on click popup will open with scroll functionality
  2. Name (direct databound)
  3. Amenities (icon(s)) - dynamically add from db.
  4. No. of room as per room type (asp.net dropdown control) - dynamically add from db and on selected index changed, need another dropdown bind in same row and on change of adult dropdown price will vary.
  5. Total price (direct databound)
  6. Book now (button)

enter image description here

Now issue is whenever any event of datalist(click on romm-image or dropdown selected index changed) fired, the dynamic control remove like ammenities, dynamic dropdown of other row etc.

What I tried as :- ispostback, relevant event of page-life cycle, ajax-jquery, viewstate.

I checked this also, But no luck. : Dynamically added controls in Asp.Net

I analyze that, the user-control is always rebound and then event fired, but no datalist rebind and thus no - databound event fire and finally dynamic control is removed. If you wish, I will share the code too (but its huge code).

So question is how to retain the dynamic controls and its value when dropdown selected index changed or image click event fired in datalist in usercontrol?

I am not used update-panel, does that work? If yes, then please give sample data.

Good to answer with sample data. Even please suggest that if possible via any other control like grid-view or else, then I ready to change it.

Updated This is my code

Load User Control code In aspx page, usercontrol define to load another user control as per current step. This “uc” user control tag in aspx page.

<div id="divPlaceholder" runat="server">
        <uc:DynamicControlHost ID="ucDynamicControlHost" runat="server" />
 </div>

In page_load as well as page_prerender( ispostback ) , the below code execute to load runtime user-control.

public Control SetUserControlPath(string path)
    {
        Control c = null;
        if (this.dynamicAllContent.Controls.Count > 0)
        {
            //Check that the new control is not the same as the current control
            if (!this.UserControlPath.Equals(path))
            {
                //Remove the old item because we can not simply replace them!
                this.dynamicPHAllContent.Controls.Clear();
                c = Page.LoadControl(path + ".ascx");
                c.ID = path;

                //Add New Item
                this.dynamicAllContent.Controls.Add(c);
                lock (_userControlLockObject)
                { 
                    //Store the new path
                    _strUserControl = path;
                }
            }
        }
        else
        {

                c = Page.LoadControl(path + ".ascx");
                c.ID = path;
                this.dynamicAllContent.Controls.Add(c);
                _strUserControl = path;

        }
        return c;
    }

Structure of datalist in usercontrol

<asp:UpdatePanel ID="EmployeesUpdatePanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>          
<asp:DataList ID="dlLodgingAvailableDetails" ShowHeader="true" OnSelectedIndexChanged="dlLodgingAvailableDetails_SelectedIndexChanged" runat="server" CellPadding="2" CellSpacing="2" BorderWidth="1px" BorderColor="Black" 
    OnItemDataBound="dlLodgingAvailableDetails_ItemDataBound" BorderStyle="Solid" GridLines="Horizontal" HorizontalAlign="Justify">
    <HeaderStyle CssClass="submit_butt"></HeaderStyle>
    <HeaderTemplate>           
     Lodging Item Type Details
     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <asp:Button ID="btnBookRoom" runat="server" Text="Book Rooms" CssClass="submit_butt" OnClick="btnBookRoom_Click" />
    </HeaderTemplate>        
    <ItemTemplate>
        <table cellpadding="2" cellspacing="0" border="1" style="width: 100%";>
            <tr>                
                <td style="width:170px">                    
                    <asp:ImageButton ID="imgLodging" OnClick="imgLodging_Click" commandargument='<%# Eval("ItemTypeId") %>'
                    runat="server" ImageUrl='<%# Eval("Photo") %>' Width="150px" Height="120px" />
                </td>               
                <td style="width:180px">
                <b>Name</b><br />
                 <span><%# Eval("ItemTypeName") %></span><br />
                <b>Occupancy</b>&nbsp;<span><%# Eval("Occupancy") %></span>
                    <br />&nbsp;
                    <asp:panel ID="placeholderAmmenities"  runat="server" Visible="True" ></asp:panel>
                 </td>
                <td style="width:100px">                    
                    <b>Room</b><br />
                     <asp:hiddenfield runat="server"  ID="hdnItemTypeId" Value='<%# Eval("LodgingItemTypeId") %>' />
                     <asp:DropDownList ID="ddlAvailable"  runat="server" 
                      AppendDataBoundItems="True" SelectedValue='<%# Bind("LodgingReservationsAvailable") %>' >
                         <asp:ListItem Value="0" Text="0"/>
                         <asp:ListItem Value="1" Text="1"/>
                         <asp:ListItem Value="2" Text="2"/>
                     </asp:DropDownList>                   
                </td>
                <td>

                </td>
                <td style="width:100px">
                    <div id="dvadult" runat="server"></div>
                    <asp:placeholder runat="server" ID="PlaceHolderAdult" ViewStateMode="Enabled" EnableTheming="False" Visible="True" ></asp:placeholder>
                </td>
                <td style="width:50px">
                      <asp:Label runat="server"  ID="lblnumbernight" ></asp:Label>
                </td>
                <td style="width:50px">
                      <asp:placeholder ID="placeholderPrice" runat="server" Visible="True"></asp:placeholder>
                </td>
                <td style="width:50px">
                 <b>Total</b><br />
                     <asp:Label runat="server" ID="lblTotalAmount" ></asp:Label>
                </td>
                <td style="width:100px">
                 <asp:Button ID="btnBookRoom" runat="server" Text="Book Rooms" CssClass="submit_butt" />
                </td>
            </tr>           
        </table>
    </ItemTemplate>
    <SeparatorStyle BackColor="Lime" Font-Bold="False" Font-Italic="False" Font-Overline="False" Font-Strikeout="False" Font-Underline="False" HorizontalAlign="Center" />
</asp:DataList>
</ContentTemplate>
</asp:UpdatePanel>

Datalist item data bound event code (its inside image binding , price related field add and also creating the dynamic control as per the condition)

  protected void dlLodgingAvailableDetails_ItemDataBound(object sender, DataListItemEventArgs e)
    {
        try
        {
            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {                    
                Image img = e.Item.FindControl("imgLodging") as Image;
                if (img != null)
                {
                    string bytesval = ((System.Data.DataRowView)(e.Item.DataItem)).Row.ItemArray[3].ToString();
                    if (string.IsNullOrWhiteSpace(bytesval)) return;
                    byte[] bytes = (byte[])((System.Data.DataRowView)(e.Item.DataItem)).Row.ItemArray[3];
                    string base64String = Convert.ToBase64String(bytes, 0, bytes.Length);
                    img.ImageUrl = "data:image/png;base64," + base64String;
                }
                DropDownList ddlList = e.Item.FindControl("ddlAvailable") as DropDownList;
                Label lbldipositamount = e.Item.FindControl("lblTotalAmount") as Label;
                Label lblnumbernight = e.Item.FindControl("lblnumbernight") as Label;
                var PlaceHolderAmmenities = e.Item.FindControl("placeholderAmmenities") as Panel;
                ddlList.Attributes.Add("onchange", " openLodgingNumber1(this,'" + ddlList.SelectedValue + "');");
                int? LodgingItemTypeId = Convert.ToInt32(((System.Data.DataRowView)(e.Item.DataItem)).Row.ItemArray[1]);
                DataSet ds = new DataSet();
                ds = LodgingData.SelectLodgingItemTypeAmenityDateSet(LodgingItemTypeId);

                DataTable dt = new DataTable();
                if (ds != null)
                {
                    dt = ds.Tables[0];
                    if (dt.Rows.Count > 0)
                    {
                        for (int j = 0; j < dt.Rows.Count; j++)
                        {
                            Image image = new Image();
                            image.ID = "imgAmmenities" + j + DateTime.Now.ToString();
                            string bytesval = dt.Rows[j]["AmenityIcon"].ToString(); //((System.Data.DataRowView)(e.Item.DataItem)).Row.ItemArray[4].ToStrin();
                            //if (string.IsNullOrWhiteSpace(bytesval)) return;
                            if (bytesval != string.Empty)
                            {
                                byte[] bytes = (byte[])dt.Rows[j]["AmenityIcon"];
                                string base64String = Convert.ToBase64String(bytes, 0, bytes.Length);
                                image.ImageUrl = "data:image/png;base64," + base64String;
                                image.Height = 20;
                                image.Width = 20;
                                image.EnableViewState = true;                                    
                                PlaceHolderAmmenities.Controls.Add(image);
                                PlaceHolderAmmenities.Controls.Add(new LiteralControl("&nbsp;"));
                            }
                        }
                    }
                }

                decimal PriceTotal = 0;
                var PlaceHolderPrice = e.Item.FindControl("placeholderPrice") as PlaceHolder;
                DataSet dsprice = new DataSet();
                dsprice = LodgingData.SelectLodgingItemTypePrice(LodgingItemTypeId);
                if (dsprice != null)
                {
                    DataTable dtprice = new DataTable();
                    dtprice = dsprice.Tables[0];
                    if (dtprice.Rows.Count > 0)
                    {
                        DateTime fromdate = Convert.ToDateTime(txtFromDate.Text);
                        DateTime todate = Convert.ToDateTime(txtToDate.Text);
                        double daterange = ((todate - fromdate).TotalDays + 1);
                        lblnumbernight.Text = daterange.ToString();

                        //for (DateTime date = fromdate; date >= todate; date.AddDays(1))
                        for (int d = 0; d < Convert.ToInt32(daterange); d++ )
                        {
                            DateTime date = fromdate.AddDays(d);
                            //DataView dv = new DataView(dtprice);
                            DataTable dtprice1 = new DataTable();
                            DataRow[] rows = dtprice.Select("#" + date + "# >= PriceStartDate AND" + "#" + date + "# <= PriceEndDate");           
                            if (rows.Length > 0)
                            {
                                dtprice1 = rows.CopyToDataTable();
                            }
                            if (dtprice1.Rows.Count > 0)
                            {
                                for (int j = 0; j < dtprice1.Rows.Count; j++)
                                {
                                    Label lbl = new Label();
                                    string dayofweek = dtprice1.Rows[j]["DayOfWeekId"].ToString();
                                    if (dayofweek.Trim() == eDayOfWeek.All.ToString().Trim())
                                    {
                                        lbl.ID = "lbl" + j;
                                        lbl.Text = dtprice1.Rows[j]["Price"].ToString();
                                        PriceTotal += Convert.ToDecimal(dtprice1.Rows[j]["Price"]);                                            
                                        PlaceHolderPrice.Controls.Add(lbl);
                                        PlaceHolderPrice.Controls.Add(new LiteralControl("<br />"));
                                    }
                                    else if (Convert.ToInt32(dayofweek) == Convert.ToInt32(date.DayOfWeek + 1))
                                    {
                                        lbl.ID = "lbl" + j;
                                        lbl.Text = dtprice1.Rows[j]["Price"].ToString();
                                        PriceTotal += Convert.ToDecimal(dtprice1.Rows[j]["Price"]);
                                        PlaceHolderPrice.Controls.Add(lbl);
                                        PlaceHolderPrice.Controls.Add(new LiteralControl("<br />"));
                                    }
                                }
                            }
                            else
                            {
                                DataView dv1 = new DataView(dtprice);
                                dv1.RowFilter = "PriceStartDate IS NULL OR PriceEndDate IS NULL";
                                //dv1.RowFilter = "PriceStartDate == null and  PriceEndDate == null";
                                DataTable dtprice2 = new DataTable();
                                dtprice2 = dv1.ToTable();
                                for (int j = 0; j < dtprice2.Rows.Count; j++)
                                {
                                    Label lbl = new Label();
                                    string dayofweek = dtprice2.Rows[j]["DayOfWeekId"].ToString();
                                    if (dayofweek.Trim() == eDayOfWeek.All.ToString().Trim())
                                    {
                                        lbl.ID = "lbl" + j;
                                        lbl.Text = dtprice2.Rows[j]["Price"].ToString();
                                        PriceTotal += Convert.ToDecimal(dtprice2.Rows[j]["Price"]);
                                        PlaceHolderPrice.Controls.Add(lbl);
                                        PlaceHolderPrice.Controls.Add(new LiteralControl("<br />"));
                                    }
                                    else if (Convert.ToInt32(dayofweek) == Convert.ToInt32(date.DayOfWeek + 1))
                                    {
                                        lbl.ID = "lbl" + j;
                                        lbl.Text = dtprice2.Rows[j]["Price"].ToString();
                                        PriceTotal += Convert.ToDecimal(dtprice2.Rows[j]["Price"]);
                                        PlaceHolderPrice.Controls.Add(lbl);
                                        PlaceHolderPrice.Controls.Add(new LiteralControl("<br />"));

                                    }
                                }
                            }
                        }
                    }
                }
                lbldipositamount.Text = PriceTotal.ToString();
                // var amount = ((System.Data.DataRowView)(e.Item.DataItem)).Row.ItemArray[3];
                int selectedvalue = Convert.ToInt32(ddlList.SelectedItem.Text);
                if (selectedvalue != 0)
                {
                    double totalamount = selectedvalue * Convert.ToDouble(PriceTotal);
                    lbldipositamount.Text = totalamount.ToString();
                }
            }
        }
        catch (Exception)
        {
            throw;
        }
    }

On dynamically genereted dropdown selection event fired

In above even add this dropdown dynamically, now when this control's event is called , further dynamic control is adding as per the condition.

Issue is this event remove the dynamic other control as well even for other row of the previous selection is hidden or lost , so we retain the dynamic control in any post back and event fire.

protected void ddlAvailable_SelectedIndexChanged(object sender, EventArgs e)
    {
        // if (UserControlTextBoxChanged != null) dlLodgingAvailableDetails_ItemDataBound(sender, e);
        //dlLodgingAvailableDetails.ItemDataBound += new DataListItemEventHandler(dlLodgingAvailableDetails_ItemDataBound);
        double amount = 0;
        var ddlList = (DropDownList)sender;
        var row = (DataListItem)ddlList.NamingContainer;
        //get the Id of the row
        DataSet ds = new DataSet();
        int? Id = Convert.ToInt32(((HiddenField)row.FindControl("hdnItemTypeId")).Value);
        double? tamount = Convert.ToDouble(((Label)row.FindControl("lblTotalAmount")).Text);
        int? groupid = Convert.ToInt32(ddlLodgingGroup.SelectedValue);
        int selectedvalue = Convert.ToInt32(ddlList.SelectedItem.Text);
        DateTime? startdate = Convert.ToDateTime(txtFromDate.Text);
        DateTime? enddate = Convert.ToDateTime(txtToDate.Text);
        ds = LodgingData.SelectLodgingItemTypeDataSet(startdate, enddate, groupid);
        DataTable dt = new DataTable();
        DataView dv = new DataView();
        if (ds != null)
        {
            dt = ds.Tables[0];
            dv = dt.DefaultView;
            dv.RowFilter = "LodgingItemTypeId=" + Id;
        }
        dt = dv.ToTable();
        if (dt.Rows.Count > 0)
        {
            if (tamount != null)
            {
                amount = Convert.ToDouble(tamount);
            }
        }
        //amount = Convert.ToDouble(((Label)row.FindControl("lblTotalAmount")).Text);            
        var PlaceHolder1 = ((PlaceHolder)row.FindControl("PlaceHolderAdult"));
        double totalamount = 0;
        if (selectedvalue != 0)
        {
            totalamount = selectedvalue * Convert.ToDouble(amount);
            ((Label)row.FindControl("lblTotalAmount")).Text = totalamount.ToString();
            Label lblAdult = new Label();
            lblAdult.ID = "lblAdult";
            lblAdult.Text = "Adult";
            lblAdult.Font.Bold = true;
            PlaceHolder1.Controls.Add(lblAdult);
            PlaceHolder1.Controls.Add(new LiteralControl("<br />"));
        }
        else
        {
            totalamount = amount;
        }
        for (int j = 0; j < selectedvalue; j++)
        {
            DropDownList ComboBox = new DropDownList();
            ComboBox.ID = "ComboBox" + j;
            ComboBox.AutoPostBack = false;
            ComboBox.Attributes.Add("runat", "server");
            ComboBox.Items.Add(new ListItem("0", "0"));
            ComboBox.Items.Add(new ListItem("1", "1"));
            ComboBox.Items.Add(new ListItem("2", "2"));
            ComboBox.SelectedIndexChanged += new EventHandler(Dynamic_Method);
            PlaceHolder1.Controls.Add(ComboBox);
            PlaceHolder1.Controls.Add(new LiteralControl("<br />"));
        }
    }

Solution

  • I'm not sure how much this will solve for you, but here is an example of preserving a row of data in a gridview with a templatefield containing a dynamically generated dropdownlist

    I broke the process into 2 parts 1) Save data currently in Gridview to a session variable 2) Recreate, source, and bind controls

    Here's saving the values in the gridview. I use a recursive find control formula I found on this site (but don't remember from where) because my controls are generated and placed inside the gridview row without unique names. For ex. the tbxA that exists in row 1 is different than the tbxA in row 2. This may not apply to you - the key is to find all controls you want to save the values of.

    Private Sub SaveValues()
        Dim savedTable As New DataTable
        savedTable.Columns.Add(New DataColumn("A"))
        For i = 0 To GridView1.Rows.Count - 1
            Dim existing(0) As Object
            existing(0) = TryCast(FindControlRecursive(GridView1.Rows(i), "ddlA"), DropDownList).SelectedValue
            savedTable.Rows.Add(existing)
        Next
        Session("GhostTable") = savedTable
    End Sub
    

    Then in Page_Load under(when it IS a postback) set the gridview datasource to the session variable, and databind it. This will trigger the following code for every row: Keep in mind I also have the datasource of the dropdown list stored in a session variable on page load. This allows the datasource and databind to occur for the dropdown every time it is generated.

    Protected Sub OnRowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
        'Handles databinding of each gridview1 row ddl to gridview templatefield
        If e.Row.RowType = DataControlRowType.DataRow Then
            Dim ddlA As New DropDownList()
            ddlA.DataSource = Session("lengthList")
            ddlA.DataBind()
            ddlA.ID = "ddlA"
            ddlA.SelectedValue = TryCast(e.Row.DataItem, DataRowView).Row.Item("A").ToString()
            e.Row.Cells(1).Controls.Add(ddlA)
        End if
    End Sub
    

    The ddlA.SelectedValue = TryCast(e.Row.DataItem, DataRowView).Row.Item("A").ToString() is what preserves the data after any postback. It determines which row is being bound, and then repopulates the control with whatever it previously was.

    Hope this helps!

    To make sure that the gridview is populated every time, call SaveValues in your event handlers.

    Protected Sub ddlEmpNumber_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ddlEmpNumber.SelectedIndexChanged
         'Do whatever on selected index change, then the following:
         Call SaveValues()
         GridView1.DataSource = Session("GhostTable")
         GridView1.DataBind()
    End Sub