Remove()函数似乎一次只能删除几个控件

时间:2016-12-22 00:28:49

标签: c# winforms

我试图在Windows窗体应用程序中一次删除多个控件(文本框和复选框)。基本上,我有一行文本框和一个相应的复选框。当"删除行"单击按钮,它应删除已选择的所有行。但它似乎一次只删除两个或三个(每行相同的两个或三个,但似乎没有任何理由它选择相同的两个或三个)。我附上了一些屏幕截图,显示了正在发生的事情。

在这里,我选择了几行:

点击删除一次后:

两次点击删除后:

这只显示每个元素的名称。如您所见,每行的名称相同:

以下是相关代码:

//Gets a list of all ticked checkboxes
public List<string> checkForChecked()
{
    var allCheckboxes = tabPage1.GetAllControlsOfType<CheckBox>();
    int count = allCheckboxes.Count<CheckBox>();
    List<string> checkedChecks = new List<string>();
    foreach(Control c in tabPage1.Controls)
    {
        if(c is CheckBox && ((CheckBox)c).Checked)
        {
            checkedChecks.Add(c.Name.ToString());
        }
    }
    return checkedChecks;
}

//The button click. Loop through elements and remove ones with the right name
private void button2_Click(object sender, System.EventArgs e)
{
    List<string> toDelete = checkForChecked();
    foreach (var val in toDelete)
    {
        foreach (Control item in tabPage1.Controls.OfType<Control>())
        {
            if (item.Name == val.ToString())
            {
                tabPage1.Controls.Remove(item);
            }

        }
    }
}

我使用的是Windows窗体应用,没有使用asp或其他网络技术。

3 个答案:

答案 0 :(得分:1)

在枚举时从集合中删除项目是一个常见错误。例如:

foreach (Control c in Controls)
    Controls.Remove(c);

将仅删除一半控件并保留每一秒控件。

一般问题的一些常见解决方案是:

  • 从集合的末尾开始以相反的顺序删除项目
  • 删除第一个找到的项目,直到找不到任何项目
  • 枚举集合的副本

在您的情况下,两种方法都可以组合成这样的方式(.Find返回Control[]):

foreach (var cb in tabPage1.Controls.OfType<CheckBox>())
    if (cb.Checked)
        foreach (var c in tabPage1.Controls.Find(cb.Name, false))
            tabPage1.Controls.Remove(c)

答案 1 :(得分:0)

您可以尝试更多类似的内容:

    private void button2_Click(object sender, EventArgs e)
    {
        List<CheckBox> CheckedBoxes = new List<CheckBox>();
        foreach (CheckBox cb in tabPage1.Controls.OfType<CheckBox>())
        {
            if (cb.Checked)
            {
                CheckedBoxes.Add(cb);    
            }
        }
        foreach (CheckBox cb in CheckedBoxes)
        {
            string cbName = cb.Name;
            cb.Dispose();
            // ... probably more code in here to find the other controls
            // ... in the "row" based on "cbName"
        }
    }

答案 2 :(得分:0)

您正在迭代控件集合并删除一个控件,每次调用Remove()方法时,该控件都会影响集合中每个项目的索引。这可能会与foreach中的迭代器混淆,从而导致“跳过”行为。从任何控件集合中删除时,最好不要同时迭代它。此外,当您在要删除项目的Controls集合上循环时,请将循环编码为迭代器向后工作。

    for (var i=Parent.Controls.Count-1; i >=0; i--)
    {
         if (someCondition) Parent.Controls.Remove(Parent.Controls[i]);
    }

以下是您的代码的清洁版本。从CheckForChecked方法返回的列表现在是一个控件列表,它比控件名称列表更容易使用。

在删除中,我们正在迭代要删除的事物列表,而不是我们要删除的控件集合。

     //Gets a list of all ticked checkboxes
     public List<Control> CheckForChecked()
        {
            var tabPage1 = new TabPage();
            var results = new List<Control>(0);
            results.AddRange(from Control c in tabPage1.Controls
                             where c is CheckBox && (c as CheckBox).Checked
                             select c);
            return results;
        }

      //The button click. Loop through elements and remove ones with the right name
      private void button2_Click(object sender, System.EventArgs e)
      {
          var toDelete = CheckForChecked();
          var tabPage1 = new TabPage();

          foreach (var val in toDelete.Where(val => tabPage1.Controls.Contains(val)))
          {
              tabPage1.Controls.Remove(val);
          }
      }        

希望这有助于某人。