Способ удаления текстовых полей с панели

61
8

У меня есть метод в приложении формы Windows, который пытается удалить 2 текстовые поля с панели.

В методе я просматриваю все элементы управления на панели. Всегда должны быть сняты две панели и добавлены вместе, но при удалении она случайно удаляет 1 или 2 контейнера, когда я нажимаю кнопку.

Вот код для удаления текстовых полей:

private void removeRows()
{
string descName = "Desc" + (textBoxCounter - 1).ToString();
string costName = "Cost" + (textBoxCounter - 1).ToString();

if (textBoxCounter >= 0)
{
foreach (Control c in costItems.Controls)
{
if (c.Name == descName)
{
// Remove the control from the panel and dispose of it
panel.Controls.Remove(c);
c.Dispose();

}
if(c.Name == costName)
{
// Remove the control from the panel and dispose of it
panel.Controls.Remove(c);
c.Dispose();
}
}

// Decrement the counter
// This happens only once since two controls need to be removed
if (textBoxCounter == 0)
textBoxCounter = 0;
else
textBoxCounter--;
}
else
MessageBox.Show("There are no more rows to remove", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

testlabel1.Text = textBoxCounter.ToString();
testlabel2.Text = panel.Controls.Count.ToString();
}

Вот код для добавления кнопки:

private void addRows(string desc, string cost)
{
if (textBoxCounter >= maxExpenses)
{
MessageBox.Show("Maximum number of expenses entered", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
TextBox Desc = new TextBox();
TextBox Cost = new TextBox();

// Give the text boxes names
Desc.Name = "Desc" + textBoxCounter.ToString();
Cost.Name = "Cost" + textBoxCounter.ToString();

// Format the text boxes
Desc.Width = panel.Width / 2;
Cost.Width = panel.Width / 4;

// Add the items to the costItems panel
panel.Controls.Add(expenseDesc);
panel.Controls.Add(expenseCost);

// Add the items to the expenses dictionary
panel.Add(Desc, Cost);

// Increment the text box counter variable
textBoxCounter++;
testlabel1.Text = textBoxCounter.ToString();
testlabel2.Text = costItems.Controls.Count.ToString();
}
}

Некоторая информация, которую нужно знать. Всегда будет добавлено и удалено 2 текстовых поля, они связаны друг с другом. TextBoxCounter инициализируется до 0, поэтому первые два имени boxe будут "Desc0" и "Cost0".

Когда я нажимаю кнопку, чтобы удалить строки в первый раз, одно текстовое поле удаляется, а затем, если я нажму его снова, он может удалить 2, он может удалить только 1.

Я попробовал отладку, и я заметил, что цикл foreach, который выполняет итерации по всем элементам управления на панели, кажется, зацикливается на один раз, не дожидаясь полного количества элементов управления.

Любая помощь с моим кодом будет отличной.

спросил(а) 2021-01-28T00:23:33+03:00 1 месяц назад
1
Решение
61

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

panel.Controls.Clear();

Или итерации назад, опираясь на индексы:

for (int i = panel.Controls.Count - 1; i >= 0; i--)
{
panel.Controls.RemoveAt(i);
}

Что касается Dispose, вы можете использовать его, если хотите, но не нужно использовать Remove:

for (int i = panel.Controls.Count - 1; i >= 0; i--)
{
panel.Controls[i].Dispose();
}

PS: Я спросил что-то подобное этому и получил -6. Одна из причин для поддержания этого вопроса была точно полезной для других (я видел код, который вы используете для удаления элементов управления в Интернете, и я знал, что его используют несколько человек). Довольно иронично.

ответил(а) 2021-01-28T00:23:33+03:00 1 месяц назад
61

Ваша проблема вызвана foreach, изменение коллекции в foreach может привести к неожиданному поведению. Вы просто хотите удалить TextBoxes с известными именами, поэтому почему бы не использовать метод ControlCollection.RemoveByKey?

Если вы хотите удалить последние добавленные текстовые поля (Desc... и Cost...), выполните следующие действия:

panel.Controls.RemoveByKey(descName);
panel.Controls.RemoveByKey(costName);

Если вы хотите, чтобы удалить все добавленные Textboxes (предположим, у вас есть другие виды TextBoxes, в противном случае мы можем использовать немного LINQ, чтобы удалить все текстовые поля легко):

for(int i = 0; i < textBoxCounter; i++){
panel.Controls.RemoveByKey("Desc" + i);
panel.Controls.RemoveByKey("Cost" + i);
}

ответил(а) 2021-01-28T00:23:33+03:00 1 месяц назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема