Search code examples
c#asp.netgridviewrepeater

List not storing item properly


I am trying to do like from the collapsible panel extender, I select few rows by checking the checkbox. After I marked them checked and click the add button, I store them into a list and display the added item in a gridview. After that, I went to another gridview which I setup using repeater, I select another few items, then it will be added into the list and the previously added items will still be there. Here is how I setup my gridview using repeater:

<asp:Repeater ID="Repeater1" runat="server" OnItemDataBound="Repeater1_ItemDataBound">
                            <ItemTemplate>
                                <!-- COLLAPSIBLE PANEL EXTENDER -->
                                <asp:Panel ID="pHeader1" runat="server" CssClass="cpHeader">
                                    <!-- Collapsible panel extender header -->
                                    <div class="form-group" style="background-color: #ffb848; height: 30px; vertical-align: middle">
                                        <div class="col-md-6">
                                            <div style="float: left; color: White; padding: 5px 5px 0 0">
                                                <asp:Label ID="lblProduct" Text='<%# DataBinder.Eval(Container.DataItem, "name") %>' runat="server" />
                                            </div>
                                        </div>
                                        <div class="col-md-6">
                                            <div style="float: right; color: White; padding: 5px 5px 0 0">
                                                <asp:Label ID="lblHeaderText1" runat="server" />
                                            </div>
                                        </div>
                                        <div style="clear: both"></div>
                                    </div>
                                </asp:Panel>
                                <!-- Collapsible panel extender body -->
                                <asp:Panel ID="pBody1" runat="server" CssClass="cpBody">
                                    <asp:Label ID="lblBodyText1" runat="server" />
                                    <!-- Grid view to show products based on each category -->
                                    <asp:GridView ID="gvProduct" runat="server" AutoGenerateColumns="False" Width="740px" CellPadding="2" ForeColor="#333333" GridLines="None" ShowHeader="False" DataKeyNames="id">
                                        <AlternatingRowStyle BackColor="White" ForeColor="#284775" />
                                        <Columns>
                                            <asp:TemplateField ItemStyle-HorizontalAlign="Center">
                                                <ItemTemplate>
                                                    <asp:CheckBox ID="cbCheckRow" runat="server" ItemStyle-Width="50px" />
                                                </ItemTemplate>
                                            </asp:TemplateField>
                                            <asp:BoundField DataField="id" HeaderText="Name" ItemStyle-Width="50px" />
                                            <asp:BoundField DataField="description" HeaderText="Name" ItemStyle-Width="550px" />
                                            <asp:BoundField DataField="halal" HeaderText="Halal" ItemStyle-Width="50px" />
                                            <asp:BoundField DataField="unitQuantity" HeaderText="Unit Quantity" />
                                        </Columns>
                                    </asp:GridView>
                                    <br />
                                </asp:Panel>
                                <asp:CollapsiblePanelExtender ID="cpe1" runat="server" TargetControlID="pBody1" CollapseControlID="pHeader1"
                                    ExpandControlID="pHeader1" Collapsed="true" TextLabelID="lblHeaderText1" CollapsedText="Show"
                                    ExpandedText="Hide" CollapsedSize="0"
                                    ScrollContents="false">
                                </asp:CollapsiblePanelExtender>
                            </ItemTemplate>
                        </asp:Repeater>
                        <br />
                        <br />
                        <asp:Panel ID="pBody2" runat="server" CssClass="cpBody">
                            <asp:GridView ID="gvFinalised" runat="server" AutoGenerateColumns="False" CellPadding="2" ForeColor="#333333" GridLines="None" Width="740px" DataKeyNames="id">
                                <Columns>
                                    <asp:BoundField DataField="categoryName" HeaderText="Category" />
                                    <asp:BoundField DataField="name" HeaderText="Product" />
                                    <asp:BoundField DataField="inventoryQuantity" HeaderText="Storage Level" />
                                    <asp:BoundField DataField="unitQuantity" HeaderText="Unit Quantity" />
                                    <asp:TemplateField HeaderText="Quantity" ItemStyle-HorizontalAlign="Center" ItemStyle-Width="200px">
                                        <ItemTemplate>
                                            <asp:TextBox ID="tbQuantity" runat="server" Width="40" Text="0" OnTextChanged="tbQuantity_TextChanged" AutoPostBack="true" />
                                            <asp:Label ID="lblCheckAmount" runat="server" ForeColor="#a94442"></asp:Label>
                                        </ItemTemplate>
                                    </asp:TemplateField>
                                </Columns>

                            </asp:GridView>
                        </asp:Panel>

There are two gridviews. One inside a repeater which show the product and product variants. Another one is outside the repeater which shows the item added into it. And the code behind:

protected void lbnAdd_Click(object sender, EventArgs e)
    {
        List<ProductPacking> prodVariantDetail = new List<ProductPacking>();

        foreach (RepeaterItem ri in Repeater1.Items)
        {
            GridView gvProduct = (GridView)ri.FindControl("gvProduct");
            foreach (GridViewRow gr in gvProduct.Rows)
            {
                CheckBox cb = (CheckBox)gr.FindControl("cbCheckRow");
                if (cb.Checked)
                {
                    // add the corresponding DataKey to idList
                    prodVariantIDList.Add(gvProduct.DataKeys[gr.RowIndex].Value.ToString());
                }
            }
        }
        for (int i = 0; i < prodVariantIDList.Count; i++)
        {
            Label1.Text += prodVariantIDList[i];
            prodVariantDetail.Add(prodPackBLL.getProdVariantDetailByID(prodVariantIDList[i]));

        }
        gvFinalised.DataSource = prodVariantDetail;
        gvFinalised.DataBind();
    }

My problem is let's say I select product variant 1,2,3 which is under canned food category. Then I went to another category and select product variant 4,5,6. The 4,5,6 which is the latest action will be displayed in the gridview but not the 1,2,3. I wonder how to fix this? Do I need something like temp list to store it?

Thanks in advance.

Edited Portion

private List<ProductPacking> prodVariantDetail
    {
        get
        {
            if (ViewState["prodVariantDetail"] == null)
            {
                return new List<ProductPacking>();
            }
            else
            {
                return (List<ProductPacking>)ViewState["prodVariantDetail"];
            }
        }
        set
        {
            ViewState["prodVariantDetail"] = value;
        }
    }

Solution

  • The problem is prodVariantIDList will always be empty when lbnAdd_Click is executed, so you need to keep the previously selected product variant ids between postbacks. I'd suggest using ViewState to store the content of prodVariantIDList.

    EDIT

    After looking at the edited portion, you can't store List<ProductPacking> in ViewState if ProductPacking class is not serializable. I'd suggest a simpler solution. First change the property:

    private List<string> SelectedVariantDetailIDs
    {
        get
        {
            if (ViewState["SelectedVariantDetailIDs"] == null)
            {
                return new List<string>();
            }
            else
            {
                return (List<string>)ViewState["SelectedVariantDetailIDs"];
            }
        }
        set
        {
            ViewState["SelectedVariantDetailIDs"] = value;
        }
    }
    

    then in lbnAdd_Click:

    protected void lbnAdd_Click(object sender, EventArgs e)
    {
        List<ProductPacking> prodVariantDetail = new List<ProductPacking>();
    
        // get the last product variant IDs from ViewState
        prodVariantIDList = this.SelectedVariantDetailIDs;
    
        foreach (RepeaterItem ri in Repeater1.Items)
        {
            GridView gvProduct = (GridView)ri.FindControl("gvProduct");
            foreach (GridViewRow gr in gvProduct.Rows)
            {
                CheckBox cb = (CheckBox)gr.FindControl("cbCheckRow");
                if (cb.Checked)
                {
                    // add the corresponding DataKey to idList
                    prodVariantIDList.Add(gvProduct.DataKeys[gr.RowIndex].Value.ToString());
                }
            }
        }
        for (int i = 0; i < prodVariantIDList.Count; i++)
        {
            Label1.Text += prodVariantIDList[i];
            prodVariantDetail.Add(prodPackBLL.getProdVariantDetailByID(prodVariantIDList[i]));
        }
        gvFinalised.DataSource = prodVariantDetail;
        gvFinalised.DataBind();
    
        // save prodVariantIDList to ViewState
        this.SelectedVariantDetailIDs = prodVariantIDList;
    }