Deleting a row from a datagrid with checkboxes???
-
Ok, I've been working on this for two days, even my instructor is lost on this one (not at all very encouraging). I'm making a shopping cart and based on which check box is selected, I need to delete that row out of the DataGrid. I'm not using SQL or any other database, though I do know its more efficient. I'm binding a DataTable to my DataGrid, and I know that I have to remove the row from the DataTable and then rebind it to the DataGrid. All of the columns and rows for the DataGrid are created in code, with the exception of the Check box column, that one I adding in HTML view. Here is a sample of how I'm creating my DataTable and then Binding it to the DataGrid, along with the Click event that should remove the row.
private void imgbutSubmit_Click(object sender, System.Web.UI.ImageClickEventArgs e) { //CREATE A DATATABLE AND PUT IT INTO SESSION STATE. DataTable dt = null; if (Session["Items"] != null) { dt = (DataTable)Session["Items"]; } else { //CREATE THE COLUMNS FOR THE DATATABLE dt = new DataTable(); dt.Columns.Add("Brand"); dt.Columns.Add("Color"); dt.Columns.Add("Material"); dt.Columns.Add("Size"); dt.Columns.Add("Quantity"); dt.Columns.Add("Price"); } //CREATE THE ROWS FOR THE DATATABLE. DataRow dr = dt.NewRow(); dr["Brand"] = drpBrand.SelectedItem.Value; dr["Color"] = drpColor.SelectedItem.Value; dr["Material"] = drpMaterial.SelectedItem.Value; dr["Size"] = null; dr["Quantity"] = txtQuantity.Text; dr["Price"] = lblPrice.Text; dt.Rows.Add(dr); //ADD THE DATATABLE TO SESSION STATE. Session["Items"] = dt; } private void Page_Load(object sender, System.EventArgs e) { //CHECK IF THERE ARE ANY ITEMS IN THE CART. if (Session["Items"] == null) { lblEmpty.Text = "There are currently no items in your shopping cart."; } //BIND THE DATATABLE TO THE DATAGRID. if (!IsPostBack) { if (Session["Items"] != null) { DataTable dt = (DataTable)Session["Items"]; PurchaseDataGrid.DataSource = dt; PurchaseDataGrid.DataBind(); PurchaseDataGrid.DataKeyField = "Remove"; } } } private void btnRemove_Click(object sender, System.EventArgs e) { DataTable dt = (DataTable)Session["Items"]; PurchaseDataGrid.DataKeyField = "Remove"; int index = 0; foreach(DataGridItem item in PurchaseDataGrid.Items) { CheckBox chkRemove = item.Cells[0].Controls[1] as CheckBox; if (chkRemove.Checked
-
Ok, I've been working on this for two days, even my instructor is lost on this one (not at all very encouraging). I'm making a shopping cart and based on which check box is selected, I need to delete that row out of the DataGrid. I'm not using SQL or any other database, though I do know its more efficient. I'm binding a DataTable to my DataGrid, and I know that I have to remove the row from the DataTable and then rebind it to the DataGrid. All of the columns and rows for the DataGrid are created in code, with the exception of the Check box column, that one I adding in HTML view. Here is a sample of how I'm creating my DataTable and then Binding it to the DataGrid, along with the Click event that should remove the row.
private void imgbutSubmit_Click(object sender, System.Web.UI.ImageClickEventArgs e) { //CREATE A DATATABLE AND PUT IT INTO SESSION STATE. DataTable dt = null; if (Session["Items"] != null) { dt = (DataTable)Session["Items"]; } else { //CREATE THE COLUMNS FOR THE DATATABLE dt = new DataTable(); dt.Columns.Add("Brand"); dt.Columns.Add("Color"); dt.Columns.Add("Material"); dt.Columns.Add("Size"); dt.Columns.Add("Quantity"); dt.Columns.Add("Price"); } //CREATE THE ROWS FOR THE DATATABLE. DataRow dr = dt.NewRow(); dr["Brand"] = drpBrand.SelectedItem.Value; dr["Color"] = drpColor.SelectedItem.Value; dr["Material"] = drpMaterial.SelectedItem.Value; dr["Size"] = null; dr["Quantity"] = txtQuantity.Text; dr["Price"] = lblPrice.Text; dt.Rows.Add(dr); //ADD THE DATATABLE TO SESSION STATE. Session["Items"] = dt; } private void Page_Load(object sender, System.EventArgs e) { //CHECK IF THERE ARE ANY ITEMS IN THE CART. if (Session["Items"] == null) { lblEmpty.Text = "There are currently no items in your shopping cart."; } //BIND THE DATATABLE TO THE DATAGRID. if (!IsPostBack) { if (Session["Items"] != null) { DataTable dt = (DataTable)Session["Items"]; PurchaseDataGrid.DataSource = dt; PurchaseDataGrid.DataBind(); PurchaseDataGrid.DataKeyField = "Remove"; } } } private void btnRemove_Click(object sender, System.EventArgs e) { DataTable dt = (DataTable)Session["Items"]; PurchaseDataGrid.DataKeyField = "Remove"; int index = 0; foreach(DataGridItem item in PurchaseDataGrid.Items) { CheckBox chkRemove = item.Cells[0].Controls[1] as CheckBox; if (chkRemove.Checked
Hi there. Whenever you inspect
DataGrid
items, realize that theDataGridItem.ItemType
may be any of a number of types, includingItem
,AlternatingItem
,Header
,Footer
, and more. My guess is that the error is occuring on this line inbtnRemove_Click()
:CheckBox chkRemove = item.Cells[0].Controls[1] as CheckBox;
It may be that you are looking at a
DataGridItem
of the ItemTypeHeader
; itsCells[0]
probably has only one literal control in it (the header text), so testingControls[1]
is probably giving an error. You would want to check theItemType
as the first line in yourforeach
block... something like this perhaps:foreach DataGridItem item in PurchaseDataGrid.Items)
{
if (item.ItemType == ListItemType.Item
|| item.ItemType == ListItemType.AlternatingItem)
{
// ... then continue with your Checkbox inspecting code
}
} -
Hi there. Whenever you inspect
DataGrid
items, realize that theDataGridItem.ItemType
may be any of a number of types, includingItem
,AlternatingItem
,Header
,Footer
, and more. My guess is that the error is occuring on this line inbtnRemove_Click()
:CheckBox chkRemove = item.Cells[0].Controls[1] as CheckBox;
It may be that you are looking at a
DataGridItem
of the ItemTypeHeader
; itsCells[0]
probably has only one literal control in it (the header text), so testingControls[1]
is probably giving an error. You would want to check theItemType
as the first line in yourforeach
block... something like this perhaps:foreach DataGridItem item in PurchaseDataGrid.Items)
{
if (item.ItemType == ListItemType.Item
|| item.ItemType == ListItemType.AlternatingItem)
{
// ... then continue with your Checkbox inspecting code
}
}Hello, I'm still getting the same error "Index out of range". Is it possibly because I specify the "int index = 0;" variable instead of a column heading? But I tried to specify a column heading and of course got a "cannot convert to string" error. See I can write:
private void btnRemove_Click(object sender, System.EventArgs e) { DataTable dt = (DataTable)Session["Items"]; // PurchaseDataGrid.DataKeyField = "Remove"; int index = 0; foreach(DataGridItem item in PurchaseDataGrid.Items) { CheckBox chkRemove = item.Cells[0].Controls[1] as CheckBox; if (chkRemove.Checked == true) { // string id = PurchaseDataGrid.DataKeys[index] as string; // DataRow[] rows = dt.Select("Item='"+ id + "'"); // rows[0].Delete(); dt.Rows[0].Delete(); } } Session["Items"] = dt; PurchaseDataGrid.DataSource = dt; PurchaseDataGrid.DataBind(); }
And this code removes the first row in the table. But this code at least checks to make sure that a checkbox is selected. Ironsmith -
Hello, I'm still getting the same error "Index out of range". Is it possibly because I specify the "int index = 0;" variable instead of a column heading? But I tried to specify a column heading and of course got a "cannot convert to string" error. See I can write:
private void btnRemove_Click(object sender, System.EventArgs e) { DataTable dt = (DataTable)Session["Items"]; // PurchaseDataGrid.DataKeyField = "Remove"; int index = 0; foreach(DataGridItem item in PurchaseDataGrid.Items) { CheckBox chkRemove = item.Cells[0].Controls[1] as CheckBox; if (chkRemove.Checked == true) { // string id = PurchaseDataGrid.DataKeys[index] as string; // DataRow[] rows = dt.Select("Item='"+ id + "'"); // rows[0].Delete(); dt.Rows[0].Delete(); } } Session["Items"] = dt; PurchaseDataGrid.DataSource = dt; PurchaseDataGrid.DataBind(); }
And this code removes the first row in the table. But this code at least checks to make sure that a checkbox is selected. IronsmithHi there. I want to make sure you understood what I meant in my original reply. In your line
CheckBox chkRemove = item.Cells[0].Controls[1] as CheckBox;
you are assuming that
item.Cells[0]
has at least twoControls
in it.Controls[0]
would reference the first, andControls[1]
would reference the second. So in your code, you are saying "assign to the variablechkRemove
a reference to the second control in the item's first cell. But what if the item's first cell doesn't contain two controls? What if it only contains one? In that case, a reference toitem.Cells[0].Controls[1]
would give an "index out of range" exception because the index "1" is out of range. In your typicalItem
, you probably do have two controls in that checkbox cell. But in, say, aHeader
item you probably only have one control in that cell (probably a header label). This is why I suggested before that you test theItemType
of the item, to make sure you are working withItem
orAlternatingItem
types only, and ignoring others (likeHeader
types). I hope this makes sense. -
Hi there. I want to make sure you understood what I meant in my original reply. In your line
CheckBox chkRemove = item.Cells[0].Controls[1] as CheckBox;
you are assuming that
item.Cells[0]
has at least twoControls
in it.Controls[0]
would reference the first, andControls[1]
would reference the second. So in your code, you are saying "assign to the variablechkRemove
a reference to the second control in the item's first cell. But what if the item's first cell doesn't contain two controls? What if it only contains one? In that case, a reference toitem.Cells[0].Controls[1]
would give an "index out of range" exception because the index "1" is out of range. In your typicalItem
, you probably do have two controls in that checkbox cell. But in, say, aHeader
item you probably only have one control in that cell (probably a header label). This is why I suggested before that you test theItemType
of the item, to make sure you are working withItem
orAlternatingItem
types only, and ignoring others (likeHeader
types). I hope this makes sense.Ok, I didn't get it the first time, but thank you for clearing that up for me. Your right, that would be referencing the header, which only says "Remove", however, I didn't put a label on it or use any templates, I just added it in HTML view. So I tried to adjust the cell and controls indexes but that didn't work out so well. so I changed Controls[1] to Controls[0]. And now I get this error "Object reference not set to an instance of an object." And its highlighting the:
if (chkRemove.Checked) {
It's not getting any further than this. Take care Ironsmith -
Ok, I didn't get it the first time, but thank you for clearing that up for me. Your right, that would be referencing the header, which only says "Remove", however, I didn't put a label on it or use any templates, I just added it in HTML view. So I tried to adjust the cell and controls indexes but that didn't work out so well. so I changed Controls[1] to Controls[0]. And now I get this error "Object reference not set to an instance of an object." And its highlighting the:
if (chkRemove.Checked) {
It's not getting any further than this. Take care IronsmithOkay - we'll get there. Each
DataGridItem
has anItemType
property that tells you what kind of row it is. If theItemType
isListItemType.Item
orListItemType.AlternatingItem
, it means it is a normal detail row. If theItemType
isListItemType.Header
, it means the item is a header row. What you want to do in your code is ignore anyDataGridItem
that represents a header row - or better put, only concern yourself with normal detail rows, identified byListItemType.Item
orListItemType.AlternatingItem
. Once you know you are working with a normal detail row, then you can grab a reference to the checkbox. Is the checkbox in the item's first cell? If so you want to referenceCells[0]
. If it's in the second cell, referenceCells[1]
, third cell is referenced byCells[2]
, and so on. Once you have the proper cell, then determine if the checkbox is the first, or second, or third, etc. control within that cell. If it is the first, then reference it withControls[0]
; if it is the second, reference it withControls[1]
; for the third,Controls[2]
, etc. Here's another shot at what I was getting at in my first response. This is yourforeach
loop, looping through eachDataGridItem
in the grid:foreach (DataGridItem item in PurchaseDataGrid.Items)
{
// first, ignore any type other than Item or AlternatingItem;
// this ensures that we won't be messing around with Headers,
// Footers, or other row types that aren't appropriate for usif (item.ItemType == ListItemType.Item
|| item.ItemType == ListItemType.AlternatingItem)
{
// now we know this item represents a normal detail row, in which
// we have a cell with a checkbox. Let's get a reference to that
// checkbox control. Assuming it's in the first cell, we'll reference
// the cell as Cells[0]. Assuming within that cell, the checkbox is
// the second control, we'll reference it with Controls[1]:CheckBox chkRemove = item.Cells\[0\].Controls\[1\] as CheckBox; // now we can test to see if the checkbox is checked or not if (chkRemove.Checked) { //... and execute any code accordingly }
}
}I hope this helps.
-
Okay - we'll get there. Each
DataGridItem
has anItemType
property that tells you what kind of row it is. If theItemType
isListItemType.Item
orListItemType.AlternatingItem
, it means it is a normal detail row. If theItemType
isListItemType.Header
, it means the item is a header row. What you want to do in your code is ignore anyDataGridItem
that represents a header row - or better put, only concern yourself with normal detail rows, identified byListItemType.Item
orListItemType.AlternatingItem
. Once you know you are working with a normal detail row, then you can grab a reference to the checkbox. Is the checkbox in the item's first cell? If so you want to referenceCells[0]
. If it's in the second cell, referenceCells[1]
, third cell is referenced byCells[2]
, and so on. Once you have the proper cell, then determine if the checkbox is the first, or second, or third, etc. control within that cell. If it is the first, then reference it withControls[0]
; if it is the second, reference it withControls[1]
; for the third,Controls[2]
, etc. Here's another shot at what I was getting at in my first response. This is yourforeach
loop, looping through eachDataGridItem
in the grid:foreach (DataGridItem item in PurchaseDataGrid.Items)
{
// first, ignore any type other than Item or AlternatingItem;
// this ensures that we won't be messing around with Headers,
// Footers, or other row types that aren't appropriate for usif (item.ItemType == ListItemType.Item
|| item.ItemType == ListItemType.AlternatingItem)
{
// now we know this item represents a normal detail row, in which
// we have a cell with a checkbox. Let's get a reference to that
// checkbox control. Assuming it's in the first cell, we'll reference
// the cell as Cells[0]. Assuming within that cell, the checkbox is
// the second control, we'll reference it with Controls[1]:CheckBox chkRemove = item.Cells\[0\].Controls\[1\] as CheckBox; // now we can test to see if the checkbox is checked or not if (chkRemove.Checked) { //... and execute any code accordingly }
}
}I hope this helps.
Ok, well it's an improvement, now its making it this far:
string id = PurchaseDataGrid.DataKeys[index] as string;
However, now I'm getting this error: "Must be non-negative and less than the size of the collection. Parameter name: index" I have no idea what this means, I'm thinking that because I don't have an "itemID" column, its conflicting with the strings in the table. But that's really just a guess. Also, should I be specifying a column name anywhere? Take care Ironsmith -
Ok, well it's an improvement, now its making it this far:
string id = PurchaseDataGrid.DataKeys[index] as string;
However, now I'm getting this error: "Must be non-negative and less than the size of the collection. Parameter name: index" I have no idea what this means, I'm thinking that because I don't have an "itemID" column, its conflicting with the strings in the table. But that's really just a guess. Also, should I be specifying a column name anywhere? Take care IronsmithIt looks like this is the code you're using to delete rows from the DataTable:
DataRow[] rows = dt.Select("Item='"+ id + "'");
rows[0].Delete();I'm guessing that the reference
rows[0]
isn't valid here. Perhapsdt.Select("Item='" + id + "'")
isn't returning any rows? Check that. I would re-read the documentation onDataKeys
andDataKeyField
as well. Make sure you understand what they are there for. You want theDataKeyField
to be a field with values that uniquely identify each row. Then you can use DataKeys[index] where index is theItemIndex
of theDataGridItem
to give you a unique id for the datarow. -
It looks like this is the code you're using to delete rows from the DataTable:
DataRow[] rows = dt.Select("Item='"+ id + "'");
rows[0].Delete();I'm guessing that the reference
rows[0]
isn't valid here. Perhapsdt.Select("Item='" + id + "'")
isn't returning any rows? Check that. I would re-read the documentation onDataKeys
andDataKeyField
as well. Make sure you understand what they are there for. You want theDataKeyField
to be a field with values that uniquely identify each row. Then you can use DataKeys[index] where index is theItemIndex
of theDataGridItem
to give you a unique id for the datarow.Well that's just it I guess, none of the values that come into the DataGrid are unique for their row. For instance the seven columns are: Remove(checkbox), Brand, Color, Size, Material, Quantity, and Price. Sometimes all the columns are populated, sometimes they are not, it depends on the Item. With the exception of the Remove column, the other six columns could be several different values. I'll look into the DataKeyFields, though I do understand what you mean, I have no uniquely identifyable row. Take care, and you've been a great help! Ironsmith