To whom this may concern, I have searched a considerable amount of time, to work a way out of this error
"Deleted row information cannot be accessed through the row"
I understand that once a row has been deleted from a datatable that it cannot be accessed in a typical fashion and this is why I am getting this error. The big issue is that I am not sure what to do to get my desired result, which I will outline below.
Basically when a row in "dg1" is deleted the row beneath it takes the place of the deleted row (obviously) and thus inherits the deleted rows index. The purpose of this method is to replace and reset the rows index (via grabbing it from the corresponding value in the dataset) that took the deleted rows place and as such the index value.
Right now I am just using a label (lblText) to try and get a response from the process, but it crashes when the last nested if statement trys to compare values.
Here is the code:
void dg1_Click(object sender, EventArgs e)
{
rowIndex = dg1.CurrentRow.Index; //gets the current rows
string value = Convert.ToString(dg1.Rows[rowIndex].Cells[0].Value);
if (ds.Tables[0].Rows[rowIndex].RowState.ToString() == "Deleted")
{
for (int i = 0; i < dg1.Rows.Count; i++)
{
if (Convert.ToString(ds.Tables[0].Rows[i][0].ToString()) == value)
// ^ **where the error is occurring**
{
lblTest.Text = "Aha!";
//when working, will place index of compared dataset value into rowState, which is displaying the current index of the row I am focussed on in 'dg1'
}
}
}
Thanks ahead of time for the help, I really did search, and if it is easy to figure out through a simple google search then allow myself to repeatably hate on me, because I DID try.
gc
You can also use the DataSet's AcceptChanges() method to apply the deletes fully.
ds.Tables[0].Rows[0].Delete();
ds.AcceptChanges();
The current value for the data column in the inner if statement will not be available for deleted rows. To retrieve a value for deleted rows, specify that you want the original value. This should fix your error:
if (Convert.ToString(ds.Tables[0].Rows[i][0, DataRowVersion.Original].ToString()) == value)
In your "crashing if", you can check if the row is deleted before accessing it's values :
if (ds.Tables[0].Rows[i].RowState != DataRowState.Deleted &&
Convert.ToString(ds.Tables[0].Rows[i][0].ToString()) == value)
{
// blaaaaa
}
Also, I'm not sure why you ToString() the RowState instead of comparing it to DataRowState.Deleted.
after deleting the row , rebind your grid with the datatable , no need to manually resetting index , datatable handels it.
so you onl;y need to rebind grid's datasource.
Related
We have a function which does the following
Given a DataRow
Creates a clone of the dataset
Imports the given row in the clone
So far, we never had any issue with this. But, there is a condition which has occured where in, the row which is created after import is skipping/nulling out some values.
I have really no clue as to why this is happening
private DataSet GetFullDataSetForCurrentRow(DataRow currentRow)
{
DataSet clone = null;
if (currentRow != null)
{
clone = currentRow.Table.DataSet.Clone();
// Get the parent row.
DataRow rootRow = GetRootRow(currentRow);
// Import the root row in the clone.
clone.Tables[rootRow.Table.TableName].ImportRow(rootRow);
// additonal code skipped...
}
return clone;
}
So, the rootRow has the correct values, but if i inspect the imported row, its loosing/skipping some values.
Check the screenshots.
https://i.imgur.com/92bLi2R.png
https://i.imgur.com/JIyHr4r.png
Found the problem.
The value that was being set in the column was larger than the size of the column.
An exception was generated but swallowed.
Thus, while importing the row, it skipped those values.
I am really not sure, how the values were stored in the first place though. Because there was an exception, it should have ideally not stored the value.
If I use OnAutoGeneratingColumn to cancel some columns that I don't necessarily want to generate, will it affect the number of columns in Table.Columns.Count?
Context
I'm iterating through a table, row by row, taking each value and passing it through to an insert SQL command. Right now it lines up so that each entry is associated properly. Will I disrupt this with e.cancel? Will row[1] no longer point to what it once did if row[0] was e.cancel'd?
for (int i = 0; i < table.Dummy.Columns.Count; i++)
{
// if we're past our first entry, add room for the next before entering it
if (i != 0)
{
InsertIntoTableQuery.AddIntPrm();
}
//if our column has an entry, add it into our table.
if (row[i] != null)
{
InsertIntoTableQuery.Prms[i].Val = row[i];
}
}
No! I figured out why I was erroring and this wasn't the cause. you can cancel column generation in the wpf datagrid without actually altering the table index's. In hindsight that's pretty obvious.
I've built a frontend to update an individual column for selected records in a GridView. I've gotten that all setup the way that I want it to work including performing a check to be sure that more than one row is selected (via a template field checkbox I added to the GridView) and that a column has been selected from a dropdown list.
I have everything down to the block of code that has to be built to do the actual update of the column for the selected rows. This will cycle through each row, so if I've selected 5 rows it would trigger this code 5 times and update the record ID associated with that row.
I'm mainly debating with myself which would be the simplest to build into this. I at first thought about doing a stored procedure on the SQL Server and feeding it the record ID, column to update, and the value to write in the update. But then I got to thinking about it and realized that I have a GridView with a Data Source that was already setup to update the record as long as I called it
In either case I'll need to refresh the GridView after the update has been completed.
Just wondering what others might think would be the cleanest approach to this and just what my options might be. I've never seen a multi row column edit implemented so figure someone may have a better idea than me on how to go about this.
Here is my code block for the update as it is right now...
protected void SaveColEditBtn_Click(object sender, EventArgs e)
{
//Read the column select drop down List into Local Varriables
String SelectedColumnItem = ColumnSelectDDL.SelectedItem.ToString();
String SelectedColumnValue = ColumnSelectDDL.SelectedValue.ToString();
List<int> EditRows = new List<int>();
List<string> recordnumber = new List<string>();
foreach (GridViewRow grv in ActVulListGV.Rows)
{
if (((CheckBox) grv.FindControl("TagRowChkBx")).Checked == true)
{
//get current row rowindex if checkbox in it is checked
EditRows.Add(grv.RowIndex);
//get the record number (RecID)
recordnumber.Add(grv.Cells[2].Text.ToString());
}
}
int[] ERows = EditRows.ToArray();
if (recordnumber.Count > 1)
{
if (ColumnSelectDDL.SelectedValue.ToString() == "TicketNumber")
{
// Save Ticket number //
}
else if (ColumnSelectDDL.SelectedValue.ToString() == "TicketClosed")
{
// Save Ticket Closed Value //
}
else if (ColumnSelectDDL.SelectedValue.ToString() == "Notes")
{
// Save Notes //
}
else if(ColumnSelectDDL.SelectedValue.ToString() == "Exception_ID")
{
// Save Exception ID //
}
EditColMsgLbl.Font.Bold = true;
SelectedRowsMsgLbl.Font.Bold = true;
ColEditPnlExt.Show();
EditColLbl.Text = SelectedColumnItem;
SelectedRowsLbl.Text = "";
foreach (string record in recordnumber)
{
// Insert the call of the procedure here to update the database
}
}
else
{
UserMessageLbl.Text = " *** Choose 2 or more rows to use column edit feature! ***";
mpePopUp.Show();
}
}
It depends. If you are updating all at once, by looping, use a Stored Procedure. However updating one by one with EditIndex, it is easier to use the source. However I would recommend using code behind and a SP to update a row, then you could use the same SP for updating a single or all rows.
See this excellent tutorial. It covers all the basics of GridView editing and updating.
And a tip if you have some time to spare in the near future, try to disable ViewState for the GridView. It will save a lot of tranfer kb's and overhead. But get the above to work first ;)
I am trying to query my DataSet and display the results in an unbound DataGridView. I feel like I am quite close with my programming logic here, but I keep getting the error ArgumentOutOfRange Exception. Index was out of range. Must be non-negative and less than the size of the collection.
My code snippet:
DataRow[] foundRows;
//Queries the Reservations table with the 'searchExpression' variable
foundRows = this.reservationMasterDataSet.Tables["Reservations"].Select(searchExpression);
//If there is at least one record found...
if (foundRows.Length > 0)
{
//Used to count our row indexes
int i = 0;
//Populate the DataGridView with the queried response
foreach (DataRow row in foundRows)
{
//Used to count our column indexes
for (int j = 0; j < reservationMasterDataSet.Tables["Reservations"].Columns.Count; j++)
{
//THIS LINE IS THROWING AN EXCEPTION
dataGridView1.Rows[i].Cells[j].Value = row.ItemArray[j];
}
i++;
}
}
My DataRow contains 12 objects so I made sure that the DataGridView has 12 columns to correspond (and there are 12 in the original database). I think I am getting the exception right away (i is still 0 in debugger). I first tried it using just row[i] but got the same error.
This is meant to be a search results pane, not an editable thing, which is why I want to only return certain results. I figured the DataGridView is the nicest and easiest way to layout the record on a Windows form.
Before you access to DataGridView1.Rows[i].Cells[j], you need to make sure DataGridView1.Rows[i] exists. If no, you need to add it to the DataGridViewRowCollection.
You can find a lot of sample on on this page.
I have a situation where I want to make a generic codebehind function to show a message row that spans the whole table. I have previously passed the Table object and the number of columns so that it could set the column span, but this is somewhat error prone as we sometimes add new columns and I have to update the column count numbers for the messages.
There doesn't seem to be any column count in the Table object and neither any way to get the TableHeaderRow that has been added in the aspx file. I'd like to avoid having to add id's to all the TableHeaderRow's as well.
Try this, should work (assuming the TableHeaderRow is the first child of the Table):
int j = 0;
foreach (Control current in tableId.Controls[0].Controls)
{
if (current.ToString() == "System.Web.UI.WebControls.TableHeaderCell")
{
j++;
}
}