Почему мой цикл foreach обрабатывает только один цикл? - PullRequest
0 голосов
/ 24 мая 2019

У меня есть кнопка в моей форме Win, которая проходит через каждую строку в моем DataGridView и при необходимости вызывает другую функцию.

Цикл и функция работают, однако, кажется, что строки пропускаются.Я выбрал 6 строк подряд, и только 3 были обработаны (в конце функции удаляется строка, только 3 из 6 были удалены).

Я подтвердил, что цикл вызывает только функцию 3из 6 раз, таким образом, проблемы, кажется, петля.

Что в мире происходит?

Вот код кнопки:

 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

Ивот вызываемая функция:

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

Ответы [ 2 ]

2 голосов
/ 24 мая 2019

Проблема здесь заключается в том, что вы удаляете строки из сетки данных при их итерации по ним.В общем, если вы хотите удалить элементы из коллекции во время итерации по ней, вам следует начать с последнего индекса и перейти к первому, чтобы избежать подобных ситуаций (когда вы удаляете элемент, индексы всех следующих элементов будутизмените на -1).

Например, вы можете заменить свой код foreach на следующий, чтобы пройти назад по строкам:

private void btnProcess_Click(object sender, EventArgs e) 
{
    for (int i = gridData.Rows.Count - 1; i > -1; i--)
    {
        DataGridViewRow row = gridData.Rows[i];

        // rest of code remains unchanged
    }
}
2 голосов
/ 24 мая 2019

Это виновник, я полагаю, в конце ApprovedBuyAction():

gridData.Rows.RemoveAt(rowNum);

Похоже, что вы удаляете строки из коллекции во время итерации по ней: Вы удаляете элемент 0, тогда прежний пункт 1 теперь равен нулю.На следующей итерации вы переходите к новому элементу 1, ранее к пункту 2.

Я удивлен, что вам это без исключения удалось.

Я предлагаю в вашем цикле через dataGrid.Rows просто составить список индексов строк, которые вы хотите удалить.После того, как этот цикл закончится, пройдитесь по списку индексов, передавая каждый из них по ApprovedBuyAction(idx); по очереди.

Вы также можете перебрать временную копию коллекции:

foreach (var row in gridData.Rows.Cast<DataGridViewRow>().ToList())
{

.... или наоборот, как предполагает Руфус.Я предпочитаю избегать циклов for, когда foreach является опцией, потому что, когда нет индекса, мне не нужно думать об индексе.Но петли for вряд ли являются ракетостроением, даже для меня.Любой из трех подходов будет работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...