title: Why is my foreach loop only processing every other one?
body: <p>I have a button on my Win Form that goes through each row in my DataGridView and calls another function as needed.</p>
  
  <p>The loop and function work, however, it seems to be skipping rows.  I selected 6 rows in a row, and only 3 got processed (at the end of the function it removes the row, only 3 of the 6 were removed).</p>
  
  <p>I confirmed that the loop only calls the function 3 of the 6 times, so the issues appears to be the loop.</p>
  
  <p>What in the world is going on?</p>
  
  <p>Here is the button code:</p>
  
  <pre><code> private void btnProcess_Click(object sender, EventArgs e) {
  
          foreach (DataGridViewRow row in gridData.Rows) {
  
              // If Approved to Buy
              if (Convert.ToBoolean(row.Cells["Approve"].EditedFormattedValue) == true) {
                  if (row.Cells["Action"].Value.ToString() == "Buy") {
                      ApprovedBuyAction(row.Index);
                  }
              }
          }
  
      }  // End btnPurchase Function
  </code></pre>
  
  <p>And here is the function being called:</p>
  
  <pre><code>private void ApprovedBuyAction(int rowNum) {
      using (SqlConnection conn = new SqlConnection(Global.connString)) {
          conn.Open();
  
          string sqlInsertQuery = "INSERT INTO PORG_Process " +
                      "(SessionID, Date, Type, BuyerID, SourceLoc, VendorID, SupplierID, Item, UOM, Qty, processFlag, deleteFlag, computerName, userName) VALUES " +
                      "(@SessionID, @Date, @Type, @BuyerID, @LocationID, @VendorID, @SupplierID, @Item, @UOM, @Qty, @processFlag, @deleteFlag, @computerName, @userName)";
  
          using (SqlCommand sqlInsert = new SqlCommand(sqlInsertQuery, conn)) {
              sqlInsert.Parameters.Add("@SessionID", SqlDbType.VarChar, 60).Value = hdnSessionID.Text;
              sqlInsert.Parameters.Add("@Date", SqlDbType.VarChar, 60).Value = DateTime.Now.ToString();
              sqlInsert.Parameters.Add("@Type", SqlDbType.VarChar, 10).Value = "PO";
              sqlInsert.Parameters.Add("@BuyerID", SqlDbType.VarChar, 60).Value = hdnBuyerID.Text;
              sqlInsert.Parameters.Add("@LocationID", SqlDbType.VarChar, 60).Value = gridData.Rows[rowNum].Cells["Location"].Value;
              sqlInsert.Parameters.Add("@VendorID", SqlDbType.VarChar, 60).Value = gridData.Rows[rowNum].Cells["Vendor"].Value;
              sqlInsert.Parameters.Add("@SupplierID", SqlDbType.VarChar, 60).Value = gridData.Rows[rowNum].Cells["Supplier"].Value;
              sqlInsert.Parameters.Add("@Item", SqlDbType.VarChar, 60).Value = gridData.Rows[rowNum].Cells["Item"].Value;
              sqlInsert.Parameters.Add("@UOM", SqlDbType.VarChar, 10).Value = gridData.Rows[rowNum].Cells["UOM"].Value;
              sqlInsert.Parameters.Add("@Qty", SqlDbType.VarChar, 60).Value = gridData.Rows[rowNum].Cells["FinalQty"].Value;
              sqlInsert.Parameters.Add("@processFlag", SqlDbType.Int).Value = 1;
              sqlInsert.Parameters.Add("@deleteFlag", SqlDbType.Int).Value = 0;
              sqlInsert.Parameters.Add("@computerName", SqlDbType.VarChar, 60).Value = hdnMachineName.Text;
              sqlInsert.Parameters.Add("@userName", SqlDbType.VarChar, 60).Value = hdnUserName.Text;
  
              sqlInsert.CommandType = CommandType.Text;
              sqlInsert.ExecuteNonQuery();
          }
  
          string sqlUpdateQuery = "UPDATE PorgReqs SET processFlag = 1 WHERE id = @TableID";
  
          using (SqlCommand sqlUpdate = new SqlCommand(sqlUpdateQuery, conn)) {
              sqlUpdate.Parameters.Add("@TableID", SqlDbType.Int).Value = gridData.Rows[rowNum].Cells["id"].Value;
  
              sqlUpdate.CommandType = CommandType.Text;
              sqlUpdate.ExecuteNonQuery();
          }
      }
  
      // Remove the Row from the Grid
      gridData.Rows.RemoveAt(rowNum);
  } // End ApprovedBuyAction Function
  </code></pre>