for statement inside a for each in c# - c#

What is wrong?
Basically want to extract each code in each row of table "Service"
And if it is equal to specific text then set each corresponding row with matching text.
foreach (DataRow code in dsAuthors.Tables["Service"].Rows)
{
for (int i = 0; i < dsAuthors.Tables[1].Rows.Count; i++)
{
if (code[1].ToString() == "01")
{
Shipment.Rows[i][0] = "Service 1";
}
else if (code[1].ToString() == "02")
{
Shipment.Rows[i][0] = "Service 2";
}
else if (code[1].ToString() == "03")
{
Shipment.Rows[i][0] = "Service 3";
}
}
}
It just fills all rows in with Service 1 but i don't want it to.
Sorry was NOT meant to have both tables be the same i have updated the code to be more accurate i believe.

You're looping on the same thing twice, then poking a value into shipment rows unbounded. It doesn't look very safe and given you're looping and setting the shipment rows through the entire collection inside the foreach, it means the last value will determine the content of ALL shipment rows.
Check it out in a debugger, you'll see that when you hit a Service 2 value, all shipment rows will be set to 2 in the loop etc.

You're iterating over the list of rows twice. You're reading data from the variable from the outer loop, and writing to the index from the inner loop. It's writing "Service 1" to all rows because the last row is "01", and the inner loop writes that to all rows.
Try this instead:
var Service = dsAuthors.Tables["Service"];
for (int i = 0; i < Service.Rows.Count; i++)
{
if (Service.Rows[i][1].ToString() == "01")
{
Shipment.Rows[i][0] = "Service 1";
}
else if (Service.Rows[i][1].ToString() == "02")
{
Shipment.Rows[i][0] = "Service 2";
}
}

Related

Comparing two DataGridViews and deleting the values of the second if exists in the first one

I am doing a code where I compare two columns of DGV roles, the first DGV (DGV1) has the raw data with duplicate roles, and the second DGV (DGV4) is a dictionary with all existing roles (no duplicates), it has to go to each row of the dictionary and if the role exists in the DGV1, it should be removed from the dictionary, leaving only the roles in the dictionary that are not currently being used in the raw data. My code is removing the roles, but when the dictionary has a value that doesn't exist in DGV1, it stops working (DGV1 continues to loop until it has an index error). Any suggestion?
NOTE: The rows in the dictionary automatically go to the first index, so there is no need to increment int i.
int eliminado = 0;
int filasDGV1 = dataGridView1.Rows.Count;
int filasDGV4 = dataGridView4.Rows.Count;
int i = 0;
int j = 0;
do
{
string perfilVacio = dataGridView4["GRANTED_ROLE", i].Value.ToString();
string perfiles = dataGridView1["GRANTED_ROLE", j].Value.ToString();
if(perfiles != perfilVacio)
{
j++;
}
else if(perfiles == perfilVacio)
{
dataGridView4.Rows.RemoveAt(i);
}
}
while (eliminado <= filasDGV4);
The first excel is DGV1 and the other is DGV2, I highlighted where is the code looping currently
The orange highlight is where the loop change in DGV1 but in the dictionary doesnt exist so its stuck there
Change your loop condition to include a test for the changing index j and also to check whether there are rows left to be eliminated.
int filasDGV1 = dataGridView1.Rows.Count;
int j = 0;
while (j < filasDGV1 && dataGridView4.Rows.Count > 0)
{
string perfilVacio = dataGridView4["GRANTED_ROLE", 0].Value.ToString();
string perfiles = dataGridView1["GRANTED_ROLE", j].Value.ToString();
if(perfiles == perfilVacio)
{
dataGridView4.Rows.RemoveAt(0);
}
else
{
j++;
}
}
If you test perfiles != perfilVacio in if you don't have to test perfiles == perfilVacio in else if, because this automatically the case. Either they are equal or they are not. There no other possibility.
Also, it is generally more readable if you ask a positive question in if like == instead of a negative one like !=.
Since i is always 0 I replaced it by the constant 0. The variable eliminado is not required (unless it is incremented when rows are removed to display the number of deleted rows).
The number of rows in dataGridView4 should not be stored in filasDGV4 as this number changes.
Update
According to your comments and the new screenshots, you need two loops. (The code above only works if both lists are sorted). We could use two nested loops; however, this is slow. Therefore, I suggest collecting the unwanted roles in a HashSet<string> first. Testing whether an item is in a HashSet is extremely fast. Then we can loop through the rows of the dictionary and delete the unwanted ones.
var unwanted = new HashSet<string>();
for (int i = 0; i < dataGridView1.Rows.Count: i++)
{
unwanted.Add(dataGridView1["GRANTED_ROLE", i].Value.ToString());
}
int row = 0;
while (row < dataGridView4.Rows.Count)
{
string perfilVacio = dataGridView4["GRANTED_ROLE", row].Value.ToString();
if(unwanted.Contains(perfilVacio))
{
dataGridView4.Rows.RemoveAt(row);
}
else
{
row++;
}
}
Suggestion: Using data binding to bind your DataGridViews to generic lists would enable you to work on these lists instead of working on the DGVs. This would simplify the data handling considerably.

Display the content of a list on a dynamically changing gridview

I have (asp) GridView with an item template inside. There are ten item templates with one textbox each. The GridView is bound in the behind code. A data table is made and depending on certain criteria only certain columns will be visible. This is how the table changes dynamically based on user criteria.
This is the code I use to collect the values inside those textboxes.
List<string> myList = new List<string>();
foreach (GridViewRow row in GridView1.Rows)
{
for (int i = 0; i < GridView1.Columns.Count; i++)
{
if (GridView1.Columns[i].Visible == true)
{
TextBox tb = (TextBox)row.FindControl($"TB{i}");
if (tb.Text == string.Empty)
{
myList.Add("Null Value");
}
else
{
string someVariableName = tb.Text;
myList.Add(tb.Text);
}
}
}
}
The TB{i} references the text boxes in the item template. They are named TB0 - TB9. This code will take the values and combine them into the list. That list will be stored in the database.
The issue I'm facing is redistributing those values back to the text boxes after that string has been queried from the database. Essentially, the string is queried and stored in a variable. That variable is then split on a comma delimiter and stored inside a new list. Here is the code I have so far, this is where the problem is.
TextBox dbInput = new TextBox();
dbInput.Text = "box1,box2,box3,box4,box5,box6,box7,box8,null,null,null,null,null,null,null,null,box13,null,null,null,null,null,null,null,null,11,222,null,null,null,null,null,null,null,null,null,null,null,null,333,null,null,null,null,444,null,333,1343";
List<string> stringList = dbInput.Text.Split(',').ToList();
int counter = 1;
foreach (GridViewRow row in GridView1.Rows)
{
for (int i = 0; i < GridView1.Columns.Count; i++)
{
if (GridView1.Columns[i].Visible == true)
{
TextBox tb = (TextBox)row.FindControl($"TB{i}");
tb.Text = stringList[i];
}
counter = counter + 1;
}
}
The input is hard coded in this instance (dbInput). I'm fairly certain the issue is this line tb.Text = stringList[i];. The reason for that is because there should only be four columns displayed with this output. It only prints the first four entries of the list into the first four boxes on row one. Then it goes to row two and prints the same four entries, repeat.
I have tried changing tb.Text = stringList[i]; [i] to another variable and incrementing it. I placed the variable outside the foreach loop but incremented it right after the inner for loop. This resulted everytime in this error Index was outside the bounds of the array.
Line 854.
Line 852: {
Line 853: TextBox tb = (TextBox)row.FindControl($"TB{i}");
Line 854: tb.Text = stringArray[counter];
Line 855: }
Line 856: counter = counter + 1;
How can I alter the code to loop through the contents of the list showing (for example) the first four items on row one, the next four items on row two and repeat till the list is empty?

C# foreach statement

I need some help with a for each statement, basically what happens is when a user edits a value within a cell, my foreach will apply this to all cells within the datagrid and change the value of them all, i need my foreach statement to work by iterating through the datagrid but only change the selected row that has been edited
try
{
//loop through each of the rows in the dgv
foreach (DataGridViewRow row in dgvDetials.SelectedRows)
{
int intQtyInsp = 0;
//if quantity inspected is empty:
if (row.Cells[2].Value.ToString() == "")
{
//quantity inspected is 0. Prevents null value errors:
intQtyInsp = 0;
}
intQtyInsp =
Int32.Parse(dgvDetials.CurrentRow.Cells[2].Value.ToString());
if (intQtyInsp < 0) // checks the cell for a negative value
{
intQtyInsp = 0; // if cells is negative submits value as Zero
}
else
{
//sets quantity inspected to value entered
intQtyInsp = Int32.Parse(row.Cells[2].Value.ToString());
}
if (intQtyInsp == 0) //if quantity inspected is 0. Ignore row.
{
}
else //else gather details and insert row as production.
{
area = dtArea2.Rows[0]["area_code"].ToString();
inspDate = dtpInspectionDate.Value.ToString("MM/dd/yyyy");
inspShift = cbShift.Text;
partNo = row.Cells[0].Value.ToString();
// dieCode = row.Cells[0].Value.ToString();
dieCode = "";
machine = "";
qtyInsp = intQtyInsp;
qtyInspRecorded = Int32.Parse(row.Cells[5].Value.ToString());
comment = "";
//machine = row.Cells[3].Value.ToString();
if (qtyInspRecorded == 0)
{
SQLMethods.insertProduction(area,
inspDate,
inspShift,
partNo,
dieCode,
qtyInsp,
comment,
machine);
}
else
{
SQLMethods.updateProduction(area,
inspDate,
inspShift,
partNo,
dieCode,
(qtyInspRecorded + qtyInsp),
comment,
machine);
}
}
}
retrieveData(); //reset values
}
catch (Exception ex)
{
MessageBox.Show(
"Error instering production values. Processed with error: "
+ ex.Message);
}
First of all, I would simplify the code here a little by splitting it into several methods that may be called from the For-loop. That would make it easier to read, and thereby easier to help you too. Just to provide an example, the following:
if (intQtyInsp < 0) // checks the cell for a negative value
{
intQtyInsp = 0; // if cells is negative submits value as Zero
}
else
{
//sets quantity inspected to value entered
intQtyInsp = Int32.Parse(row.Cells[2].Value.ToString());
}
could be replaced with something like:
int intQtyInsp = SetQuantityInspected();
Then that method could contain the if-structure. Repeat this for other parts of the code in the loop too. Trust me, this will make your life easier.
Also, it seems as if the result of this section is never used; the value of intQtyInsp is overwritten right afterwards!:
if (row.Cells[2].Value.ToString() == "")
{
//quantity inspected is 0. Prevents null value errors:
intQtyInsp = 0;
}
As for your question: I'm not sure how you would get the id of the row that is currently being edited. (If possible (?), it might be getter to loop through the table / data source behind the datagrid?).
In any case, what you need to do is something like the following inside your loop:
if(IsCurrentlyEditedRow(row)){
...
// (all the stuff currently in the body of your loop goes here)
...
}
Now you can implement the method IsCurrentlyEditedRow() to return True or False depending on whether or not the id of the current row is the the same as that of the one you are editing.
Sorry if this is not a very specific and detailed answer, hope it is of some use anyway.

Delete Multiple rows from datagridview

I've a datagridview in which values are inserted.The gridview is like this.
Item PRID
------ ------
Item1 1
Item2 2
Item3 2
I am trying to compare the PRID with a variable which holds the selected row PRID.
What I've done so far.
foreach (DataGridViewRow dgv_r in PurchaseOrder_dgv.Rows)
{
if (dgv_r.Cells[1].Value.ToString() == CurrentSelected_PRID_ForPurchaseOrder.ToString())
{
PurchaseOrder_dgv.Rows.Remove(dgv_r);
}
}
But it deletes the bottom row not the second row.and gives the following error.What I want is if the value of CurrentSelected_PRID_ForPurchaseOrder is equal to 2 then it should delete both the rows.I've tried it using for loop also but it gives me Index out of range error.It is giving the following error.
Object Reference Not set to an instance of object
The are a couple of ways around this. One is to do the following
for (int i = dataGridView1.RowCount - 1; i >= 0; i--)
if (String.Compare(dataGridView1.Rows[i].Cells[1].Value.ToString(), "2") == 0)
dataGridView1.Rows.Remove(dataGridView1.Rows[i]);
This is looping from the bottom end of the DataGridView and avoids the problem with removing rows whilst iterating.
I hope this helps.
As mellamokb pointed out the reason is because your editing the collection during the foreach. One solution would be to store the rows with the same PRID in a list first and then remove them after. Something like this
var rowsToRemove = new List<int>();
foreach (DataGridViewRow dgv_r in PurchaseOrder_dgv.Rows)
{
if (dgv_r.Cells[1].Value.ToString() == CurrentSelected_PRID_ForPurchaseOrder.ToString())
{
rowsToRemove.Add(dgv_r.Index);
}
}
rowsToRemove.Reverse();
rowsToRemove.ForEach(i => PurchaseOrder_dgv.Rows.RemoveAt(i));
Another solution is to use a while loop instead which takes into account the possiblity of the collection size changing.
int i = 0;
while (i < PurchaseOrder_dgv.Rows.Count)
{
if (PurchaseOrder_dgv.Rows[i].Cells[1].Value.ToString() == CurrentSelected_PRID_ForPurchaseOrder.ToString())
{
PurchaseOrder_dgv.Rows.RemoveAt(i);
}
i++;
}

C# Updating Data Issue

I am currently using one button for inserting/updating content within a table. It then takes the uploaded CSV and inserts or updates it into a data table depending on whether the row exists or not.
Here is the code fired after the button's OnClick:
if (ExcelDDL.SelectedValue == "Time Points" && fileName == "TimePoints.csv")
{
var GetTPoints = (SEPTA_DS.TimePointsTBLDataTable)tpta.GetDataByCategory(CategoryDDL.SelectedItem.ToString());
//Loop through each row and insert into database
int i = 0;
foreach (DataRow row in TempRouteDataTable.Rows)
{
//Gather column headers
var category = Convert.ToString(CategoryDDL.SelectedItem);
var agency = Convert.ToString(row["Agency"]);
if (agency == null || agency == "")
{
//If row is empty skip it entirely
goto skipped;
}
var route = Convert.ToString(row["Route"]);
var GetRShortName = (SEPTA_DS.RoutesTBLDataTable)rta.GetDataByRouteID(route);
var newRoute = "";
if (GetRShortName.Rows.Count > 0)
{
newRoute = Convert.ToString(GetRShortName.Rows[0]["route_short_name"]);
}
var direction = Convert.ToString(row["Direction"]);
var serviceKey = Convert.ToString(row["Service Key"]);
var language = Convert.ToString(row["Language"]);
var stopID = Convert.ToString(row["Stop ID"]);
var stopName = Convert.ToString(row["Stop Name"]);
if (stopName.Contains("accessible"))
{
string[] noHTML = stopName.Split('>');
int insertH = Convert.ToInt32(hta.InsertHandicapRow(newRoute,noHTML[2]));
}
var sequence = Convert.ToString(row["Sequence"]);
var origID = -1;
if (GetTPoints.Rows.Count > 0)
{
origID = Convert.ToInt32(GetTPoints.Rows[i]["TPointsID"]);
var GetID = (SEPTA_DS.TimePointsTBLDataTable)tpta.GetDataByID(origID);
if (GetID.Rows.Count < 1)
{
origID = -1;
}
}
if (origID == -1)
{
int insertData = Convert.ToInt32(tpta.InsertTimePoints(category, agency, newRoute, direction, serviceKey, language, stopID, stopName, sequence));
}
else
{
int updateData = Convert.ToInt32(tpta.UpdateTimePoints(category, agency, newRoute, direction, serviceKey, language, stopID, stopName, sequence, origID));
}
skipped:
i++;
}
}
You can see how I check whether to insert or update around the bottom. I am using this method across other sections of this program and it works just fine. But in this case it is distorting my datatable immensely and I can't figure out why.
This is the bottom part of my table after inserting [no items currently within the database]:
This is the table after reuploading the CSV with data already existing within the table:
I am also getting this error when updating There is no row at position 2230.
What is going wrong in the code to cause this huge shift? I am just checking to see if the ID exists and if it does update rather than insert.
Also the reason i am using goto is because there are blank rows in the document that need to be skipped.
Is your TPointsID column, a auto-generated number? If so, since you are skipping the empty row, some referential integrity problem might be occuring,because of empty data in the skipped rows in the database.
From the error : There is no row at position 2230 , it is also understood that, because of the skipping you might be trying to access some non existent row in the datatable.
Also, if possible consider using the ADO.NET DataAdapter which has got the CRUD operation capability. You can find more about it at : http://support.microsoft.com/kb/308507

Categories