0

I have an asp:Table that is populated with "products" using controls on the page (an 'add' button and a textbox for quantity). In my code behind, whenever a table item is to be added, I first create an instance of Product, set its properties, and then add it to a list of products. I then do the following with the table: - Clear its Rows collection - Add the header row - Bind the table to the list of Products - Cache the list of Products, for later use

Each row in the Table begins with a cell containing a checkbox. Beneath the Table is a "Clear All" LinkButton. When the Clear All LinkButton is clicked, I direct it to a method to cycle through all of the CheckBoxes, determine whether or not they are checked, and delete the corresponding entry in the Product list if checked == true. So, in theory, when I re-bind the Products list to the Table, the Rows with that had their CheckBoxes selected should be removed.

This works if there is a single Row in the Table: when debugging, the CheckBox's checked property shows as "true", and the row is removed. However, if there is more than one row, the checked property for all CheckBoxes appears as "false", and nothing is removed.

EDIT - It actually appears to remove the last row of the table, though the rest of the CheckBoxes are treated as not being checked.

Here is the table on the page:

<asp:Table ID="tblProducts" runat="server">
<asp:TableHeaderRow ID="tblProductsHead" runat="server" BorderStyle="Solid">
    <asp:TableHeaderCell ID="colCheckBox" runat="server" Text="">
        <asp:CheckBox ID="chkSelectAll" runat="server" Text="" />
    </asp:TableHeaderCell>
    <asp:TableHeaderCell ID="colProduct" runat="server" Text="Product"><asp:TableHeaderCell>
    <asp:TableHeaderCell ID="colValue" runat="server" Text="Value"></asp:TableHeaderCell>
    <asp:TableHeaderCell ID="colQuantity" runat="server" Text="Quantity"></asp:TableHeaderCell>
    <asp:TableHeaderCell ID="colTotalValue" runat="server" Text="Total Value"></asp:TableHeaderCell>
</asp:TableHeaderRow>
</asp:Table>
<asp:LinkButton ID="lbtnClearAll" runat="server" Text="Clear All" 
    onclick="lbtnClearAll_Click"></asp:LinkButton>

...and here are the relevent sections of the code-behind:

 private void ClearSelectedTableRows()
    {
        if (Cache["TableRows"] != null)
        {
            tableRows = Cache["TableRows"] as List<TableRow>;
            Cache.Remove("TableRows");

            TableRow row = new TableRow();
            CheckBox rowBox = new CheckBox();

            for (int i = 0; i < tableRows.Count; i++)
            {
                row = tblProducts.Rows[i+1]; // skip header row
                rowBox = row.Cells[0].Controls[0] as CheckBox;

                if (rowBox.Checked)
                    tableRows.RemoveAt(i);

            }

            TableRow headRow = tblProductsHead;
            tblProducts.Rows.Clear();
            tblProducts.Rows.Add(headRow);
            Cache.Insert("TableRows", tableRows, null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration);
            PopulateTable();                
        }
    }


private void PopulateTable()
    {
        if (Cache["TableRows"] != null)
        {
            List<TableRow> rows = Cache["TableRows"] as List<TableRow>;
            foreach (TableRow row in rows)
                tblProducts.Rows.Add(row);
        }
    }
dbr
  • 247
  • 2
  • 7
  • 24
  • 1
    Well, off the top of my head I don't see anything in particular. But how are you populating your `Cache["TableRows"]`? Perhaps it's an oversight in your creation code. Also, in your `ClearSelectedTableRows` method, `TableRow row = new TableRow();` and `CheckBox rowBox = new CheckBox()` are unnecessary; just declare them within the for loop. EDIT: Also, your for loop looks odd. You should start at `int i = 1` maybe; you "skip header row", but then three lines down you remove the current row (which could be the header row!) – Chris Sinclair Jul 10 '12 at 11:37
  • 1
    Based on your edit, try changing the line `tableRows.RemoveAt(i);` to `tableRows.RemoveAt(i + 1);` – Chris Sinclair Jul 10 '12 at 11:49
  • Thanks Chis, I'll have a gander at the code creating them. In relation to the loop: the section with i+1 is getting the value of the checkbox in the Table on the page. In the part "tableRows.RemoveAt(i)", its referring to the list that the table will be bound to, which doesn't have a header row. – dbr Jul 10 '12 at 11:58

2 Answers2

0

I also think that your loop seems odd, and agree that you should also start with i=1. A quick answer would be using --i right after removing a row

almi_n
  • 51
  • 3
  • Thanks for the answer. It may seem odd, but its working, and that's what matters to me at the minute :) Whether I add to 'i' in one place or subtract from it in another, it'll have the same end result – dbr Jul 10 '12 at 13:48
0

Someone left an answer, saying that the controls needed IDs for their properties to be properly assessed, but then deleted it. This turned out to be the root of the issue anyway. After giving the checkboxes IDs in the creation code, it began to work after a fashion.

However, further problems were then caused by using the RemoveAt() method; I was using the count of the "tableRows" list for the length of the loop, while at the same time potentially changing the length of that list inside the loop.

Its fixed now, and here's the updated method:

    private void ClearSelectedTableRows()
    {
        if (Cache["TableRows"] != null)
        {
            tableRows = Cache["TableRows"] as List<TableRow>;
            Cache.Remove("TableRows");

            TableRow row = new TableRow();
            CheckBox rowBox = new CheckBox();
            List<TableRow> rowsToRemove = new List<TableRow>();
            for (int i = 0; i < tableRows.Count; i++)
            {
                row = tblProducts.Rows[i+1]; // skip header row
                rowBox = row.Cells[0].Controls[0] as CheckBox;

                if (rowBox.Checked)
                    rowsToRemove.Add(tableRows[i]);                    
            }

            foreach (TableRow removeRow in rowsToRemove)
            {
                if (tableRows.Contains(removeRow))
                    tableRows.Remove(removeRow);
            }

            TableRow headRow = tblProductsHead;
            tblProducts.Rows.Clear();
            tblProducts.Rows.Add(headRow);
            Cache.Insert("TableRows", tableRows, null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration);
            PopulateTable();                
        }            
    }

Thanks to those who helped, and thanks to the phantom answerer!

dbr
  • 247
  • 2
  • 7
  • 24