I've gone through the other answers for this kind of question, nothing has really worked well so far.
I have a foreach loop that should add the the row from the source datagridview to the destination datagridview then remove that row from the source.
The invalid operation exception is: Row provided already belongs to a DataGridView control.
I couldn't get ...Rows.Copy() to work either. Any ideas?
foreach (DataGridViewRow selRow in fromDataGridView.SelectedRows)
{
toDataGridView.Rows.Add(selRow);
fromDataGridView.Rows.Remove(selRow);
}
You need to remove the row from fromDataGridView before you add it to toDataGridView.
But you're modifying the collection inside the foreach loop - that won't work.
The workaround is to copy the collection for use in the foreach.
Try this:
foreach (DataGridViewRow selRow in fromDataGridView.SelectedRows.OfType<DataGridViewRow>().ToArray())
{
fromDataGridView.Rows.Remove(selRow);
toDataGridView.Rows.Add(selRow);
}
Here is an example of what you could do or try..
its happening when one row is removed the rows count decrements too so if you put your code in for loop and run it in reverse it would work fine have a look:
for (int selRow = dataGridView1.Rows.Count -1; selRow >= 0 ; selRow--)
{
toDataGridView.Rows.Add(selRow);
fromDataGridView.Rows.Remove(selRow);
}
Adding a new row directly to DataGridView is not possible when there is BindingSource.
You should add row to the BindingSource of second view and let it to add the row to its grid.
I've tested the below code in a working solution.
var selectedRows = dataGridView1.SelectedRows;
int count = dataGridView1.SelectedRows.Count;
for (int i = 0; i < count; i++)
{
bindingSource2.Add(bindingSource1[selectedRows[i].Index]);
dataGridView1.Rows.Remove(selectedRows[i]);
}
Related
I have a datagridview which store a path to files with extensions and I must delete rows which are .exe extensions.
My Code:
foreach (DataGridViewRow row in dataGridViewgrida.Rows)
{
if (row.Cells[1].Value.ToString().Contains(".exe"))
row.Cells[1].Style.ForeColor = Color.Red;
dataGridViewgrida.Rows.RemoveAt(this.dataGridViewgrida.Rows.); // ?? I do not know how to do this
}
You should use reverse loop and delete row based on index:
for(int i=dataGridViewgrida.Rows.Count - 1; i>=0; i--)
{
var row = dataGridViewgrida.Rows[i];
if (row.Cells[1].Value.ToString().Contains(".exe"))
{
dataGridViewgrida.Rows.RemoveAt(i); // or dataGridViewgrida.Rows.Remove(row );
}
}
It is a bad idea to remove an item from a collection you're currently iterating over. Put the current row into a temporary collection and remove them after your foreach loop.
You cannot remove items from the collecion when you are looping it. Create a list to keep the rows you need to delete a populate it inside the loop.
Then you can remove them in another loop:
foreach(DataGridRow row in yourList)
dataGridViewgrida.Rows.Remove(item);
If I execute the following code fragment:
IXLRange dataRange = worksheet.Range(1, 1, myData.Count, 4);
foreach (var row in dataRange.Rows()) {
//int cells = row.CellCount();
if (isEndOfGroup) {
row.InsertRowsBelow(1);
var rowBelow = row.RowBelow();
// Do stuff with the added row, like adding a subtotal
}
}
What's actually happening here? It seems like the row collection being iterated on is being updated, which is what I want to happen, because the commented-out line throws an exception with the error "Range is invalid" on the next iteration, as if the row somehow hasn't been initialised yet.
I understand modifying a collection as you iterate through it is bad practice, but I've done this before without any issues.
What would be an alternative way of achieving this?
Never modify a collection while iterating... It is a bid.
Take advantage of the for loop.
When it did not raise an exception before, then you just changed the content of the row but not the reference of to row itself.
I ended up using a for loop as Bagerfahrer suggested and having a second counter to keep track of the row number:
int rowNum = 1; // Row numbering starts at 1
for (int i = 0; i < myData.Count; i++) {
var row = worksheet.Row(rowNum);
if (isEndOfGroup) {
row.InsertRowsBelow(1);
rowNum++;
var rowBelow = row.RowBelow();
// Do stuff with the added row, like adding a subtotal
}
rowNum++;
}
This allows me to index into myData for retrieving data and also keep track of where I'm writing to in the spreadsheet.
My datagridView1 contains 7 columns, and first one has dates.
I'm trying to transfer january data from dataGridView1 to dataGridView2
I did try using a loop, which logically thought it would work, but it would give me nullExceptions
Here's my code:
for (int i = 0; i < f1.dataGrivView1.Rows.Count; i++)
{
if (f1.dataGrivView1.Rows[i].Cells[0].Value.ToString().Split('/')[1].StartsWith("01"))//if january..
{
dataGrivView1.Rows.Add();//datagridview in current form
dataGrivView1.Rows[i].Cells[0].Value = f1.dataGrivView1.Rows[i].Cells[0].Value.ToString();
dataGrivView1.Rows[i].Cells[1].Value = f1.dataGrivView1.Rows[i].Cells[1].Value.ToString();
}}
And after some googling, I saw you can't just copy data this way and you need to clone it, so I tried.
foreach (DataGridViewRow dgvr in f1.dataGridView1.Rows)
{
DataGridViewRow r = dgvr.Clone() as DataGridViewRow;
foreach (DataGridViewCell cell in dgvr.Cells)
{
if (cell.Value.ToString().Contains("/01/"));
r.Cells[cell.ColumnIndex].Value = cell.Value;
}
dataGridView1.Rows.Add(r);
}
But.. same thing.
Any idea?
This does indeed copy the first column values from a DataGridView to another.
for(int i=0; i<f1.dataGridView1.Rows.Count; i++)
dataGridView1.Rows[i].Cells[0].Value = f1.dataGridView1.Rows[i].Cells[0].Value;
Any exceptions thrown are probably due to the new dataGridView1 not having the existing rows at the corresponding index in the iteration.
Could someone post some tips on what is the best way to loop through the dataGridView? I've a datagridview with large number of row and want to go through and get the cell values. I use the convention way and it take too long. Thanks in advance.
Sample code to traverse:
foreach (DataGridViewRow row in DataGridView1.Rows) {
object[] obj = new object[row.Cells.Count];
for (i = 0; i <= row.Cells.Count - 1; i++) {
obj[i] = row.Cells(i).Value; //Place your code and do type conversion
}
}
I would just bind your data to the DataGridView. This way the collection you have will be up to date and there will be no need to traverse the DataGridView to get data. See an example at C# Tutorial - Binding a DataGridView to a Collection
If you need to reach every cell, the fastest possible is O(n):
DataGridView dgv = new DataGridView();
foreach (DataGridViewRow row in dgv.Rows)
{
foreach (DataGridViewCell cell in row.Cells)
{
//
}
}
There are faster ways to update data however, like bindings.
I have a DataSet with several DataTables inside. I'm displaying the DataTables in a ListView (I didn't know about databinding when I wrote the code). Anyway, I would like to remove rows from the DataTables inside the DataSet.
I have tried this:
foreach (DataRow row in dsData.Tables["Table1"].Rows)
{
//find the row that contains the username I'm after
if (item.SubItems[2].Text == row["LoginName"].ToString())
{
dsData.Tables["Table1"].Rows.Remove(row); //<- main code of interest
}
}
I've also tried
dsData.Tables["Table1".Rows.Delete(row);
The problem I'm experiencing is that the when you remove a row I get the exception:
Collection was modified; enumeration operation might not execute.
From what I understand it's because when you remove a row from a ListView the row below it moves up and causes all this trouble. The code itself does what it's supposed to but it's not nice to see that exception when when you run it.
I was about to rewrite the whole class with a DataGridView but would rather correct that single line if possible :).
EDIT: I'm not even sure a DataGridView would solve the problem anyway.
change the loop to a for loop counting backwards so you don't get that message.
for(int i = dsData.Tables["TAble1"].Rows; i > 0; i--)
{
if(item.SubItems[2].Text == dsData.Tables["Table1"].Rows[i - 1]["LoginName"].ToString())
dsData.Tables["Table1"].Rows.Remove(i - 1)
}
Try:
DataSet dsData = new DataSet();
List<DataRow> rowsToDelete = new List<DataRow>();
foreach (DataRow row in dsData.Tables["Table1"].Rows)
{
if (item.SubItems[2].Text == row["LoginName"].ToString())
{
rowsToDelete.Add(row);
}
}
foreach(DataRow row in rowsToDelete)
{
dsData.Tables["Table1"].Rows.Remove(row);
}
You need a backwards for loop if you're going to be removing things
(explanation of why here)
for (int i = dsData.Tables["Table1"].Rows.Count - 1; i >= 0; i--)
{
DataRow row = dsData.Tables["Table1"].Rows[i];
//find the row that contains the username I'm after
if (item.SubItems[2].Text == row["LoginName"].ToString())
{
dsData.Tables["Table1"].Rows.Remove(row); //<- main code of interest
}
}
in general you can't remove items from a collection within a loop that is iterating on it
what you could do is keep a list of all the row you want to remove (creating it within the loop) and remove all of them OUTSIDE the loop
You can't modify a collection that you are iterating though with a foreach loop, from inside the loop. Do this instead:
for (int i = 0; i < dsData.Tables["Table1"].Rows.Count; i++)
{
DataRow row = dsData.Tables["Table1"].Rows[i];
if (item.SubItems[2].Text == row["LoginName"].ToString())
{
dsData.Tables["Table1"].Rows.Remove(row); //<- main code of interest
}
}