从面板中移除动态控件

22

我在Windows窗体的面板上动态生成了控件,并生成了一个用于删除这些控件的按钮,所有控件都在行中。

int c = 0;
private void button1_Click(object sender, EventArgs e)
{
    int v;
    v = c++;
    panel1.VerticalScroll.Value = VerticalScroll.Minimum;
    ComboBox combo = new ComboBox();
    combo.Name = "combobox" + v ;
    combo.Location = new Point(30, 5 + (30 * v));

    ComboBox combo2 = new ComboBox();
    combo2.Name = "combobox2" + v ;
    combo2.Location = new Point(170, 5 + (30 * v));

    TextBox txt = new TextBox();
    txt.Name = "txtbx" + v;
    txt.Location = new Point(300, 5 + (30 * v));

    TextBox txt2 = new TextBox();
    txt2.Name = "txtbx2" + v;
    txt2.Location = new Point(450, 5 + (30 * v));

    TextBox txt3 = new TextBox();
    txt3.Name = "txtbx3" + v;
    txt3.Location = new Point(600, 5 + (30 * v));

    Button btn = new Button();
    btn.Name = "btn" + v;
    btn.Text = "Remove";
    btn.Location = new Point(750, 5 + (30 * v));
    panel1.Controls.Add(combo);
    panel1.Controls.Add(btn);
    panel1.Controls.Add(txt);
    panel1.Controls.Add(combo2);
    panel1.Controls.Add(txt2);
    panel1.Controls.Add(txt3);
    btn.Click += new EventHandler(btn_Click);
    combo.Tag = btn; 
    combo2.Tag = combo; 
    btn.Tag = combo2;

}

 private void btn_Click(object sender, EventArgs e)
 {
     ComboBox cb3 = btnh.Tag as ComboBox;
     ComboBox cb4 = cb3.Tag as ComboBox;
     panel1.Controls.Remove(cb3);
     panel1.Controls.Remove(cb4);
     panel1.Controls.Remove(btnh);
  }

现在,当我点击一行中的按钮时,如何从该行中删除所有控件?


你想要移除哪些控件?全部的控件还是只有一部分?如果是后者,那么具体是哪些控件?你尝试过什么? - nawfal
我曾尝试过不同的方法,但后来听说了这个。所以我决定使用TableLayout进行工作, 我使用标签属性来绑定对象,并使用panel.controls.remove方法来移除控件,但是当我有很多控件时它不起作用, 你能帮我吗? - shariq_khan
2
它不起作用是因为你的按钮点击处理程序为空。您需要发布您编写的“不起作用”的代码,并描述它为什么“不起作用”。从您的其他帖子中,我怀疑您1.未设置标记属性,就像您在此帖子中没有设置它一样,以及2.尝试将标记转换为控件。 - PhoenixReborn
好的,我会处理,更新我的问题。 - shariq_khan
6个回答

50

你还没有说明你想要删除哪个控件,想要删除什么类型的控件或者如何识别它们。

你可以通过遍历控件来删除特定的控件。

如果你有Linq,这很容易实现:

private void btn_Click(object sender, EventArgs e)
{
    panel1.Controls.Clear(); //to remove all controls


    //to remove all comboboxes
    foreach (Control item in panel1.Controls.OfType<ComboBox>().ToList())
    {
        panel1.Controls.Remove(item); 
    }


   //to remove control by Name
    foreach (Control item in panel1.Controls.OfType<Control>().ToList())
    {
        if (item.Name == "bloodyControl")
            panel1.Controls.Remove(item); 
    }

    
    //to remove just one control, no Linq
    foreach (Control item in panel1.Controls)
    {
        if (item.Name == "bloodyControl")
        {
             panel1.Controls.Remove(item);
             break; //important step
        }
    }
}

编辑:

因为您已经给控件打了标记,所以做同样的事情很容易。您只需要从标记中取回该控件即可。 但是您需要适当地打标记:

请改用以下方法:

private void button1_Click(object sender, EventArgs e)
{
    int v;
    v = c++;
    panel1.VerticalScroll.Value = VerticalScroll.Minimum;

    Button btn = new Button();
    btn.Name = "btn" + v;
    btn.Text = "Remove";
    btn.Location = new Point(750, 5 + (30 * v));
    btn.Click += new EventHandler(btn_Click);
    
    ComboBox combo = new ComboBox();
    combo.Name = "combobox" + v ;
    combo.Location = new Point(30, 5 + (30 * v));
    combo.Tag = btn;

    ComboBox combo2 = new ComboBox();
    combo2.Name = "combobox2" + v ;
    combo2.Location = new Point(170, 5 + (30 * v));
    combo2.Tag = btn;

    TextBox txt = new TextBox();
    txt.Name = "txtbx" + v;
    txt.Location = new Point(300, 5 + (30 * v));
    txt.Tag = btn;

    TextBox txt2 = new TextBox();
    txt2.Name = "txtbx2" + v;
    txt2.Location = new Point(450, 5 + (30 * v));
    txt2.Tag = btn;

    TextBox txt3 = new TextBox();
    txt3.Name = "txtbx3" + v;
    txt3.Location = new Point(600, 5 + (30 * v));
    txt3.Tag = btn;

    panel1.Controls.Add(combo);
    panel1.Controls.Add(btn);
    panel1.Controls.Add(txt);
    panel1.Controls.Add(combo2);
    panel1.Controls.Add(txt2);
    panel1.Controls.Add(txt3);    
}

private void btn_Click(object sender, EventArgs e)
{
   //to remove control by Name
    foreach (Control item in panel1.Controls.OfType<Control>().ToList())
    {
        if (item.Tag == sender || item == sender)
            panel1.Controls.Remove(item); 
    }
}

在这里,你正在使用按钮为控件进行标记,因此在按钮单击时,可以删除所有标签为所点击的按钮的控件,该按钮来自sender参数。但是这种方法的缺点是必须枚举面板中的所有控件,这不是很好。

编辑:由于我发现下面的代码是用于表格布局面板,而OP现在没有使用它,但无论如何,表格面板布局更适合这项工作。

我建议你这样做:

private void button1_Click(object sender, EventArgs e)
{
    int v;
    v = c++;
    panel1.VerticalScroll.Value = VerticalScroll.Minimum;

    Button btn = new Button();
    btn.Name = "btn" + v;
    btn.Text = "Remove";
    btn.Location = new Point(750, 5 + (30 * v));
    btn.Click += new EventHandler(btn_Click);
    btn.Tag = v;

    ComboBox combo = new ComboBox();
    combo.Name = "combobox" + v ;
    combo.Location = new Point(30, 5 + (30 * v));
    combo.Tag = v;

    ComboBox combo2 = new ComboBox();
    combo2.Name = "combobox2" + v ;
    combo2.Location = new Point(170, 5 + (30 * v));
    combo2.Tag = v;

    TextBox txt = new TextBox();
    txt.Name = "txtbx" + v;
    txt.Location = new Point(300, 5 + (30 * v));
    txt.Tag = v;

    TextBox txt2 = new TextBox();
    txt2.Name = "txtbx2" + v;
    txt2.Location = new Point(450, 5 + (30 * v));
    txt2.Tag = v;

    TextBox txt3 = new TextBox();
    txt3.Name = "txtbx3" + v;
    txt3.Location = new Point(600, 5 + (30 * v));
    txt3.Tag = v;

    panel1.Controls.Add(combo);
    panel1.Controls.Add(btn);
    panel1.Controls.Add(txt);
    panel1.Controls.Add(combo2);
    panel1.Controls.Add(txt2);
    panel1.Controls.Add(txt3);    
}

private void btn_Click(object sender, EventArgs e)
{
    int toBeDeletedRow = (int)((Control)sender).Tag;
    for (int row = panel1.RowCount - 1; row >= 0; row--)
    {
        if (row == toBeDeletedRow)
        {
            panel1.RowStyles.RemoveAt(row);
            panel1.RowCount--;
            return;
        }
    }
}

先生,我需要删除同一行中的控件。如您所见,我的控件是通过C++迭代生成的,它们位于y轴上,因此控件在同一行中。我想要删除与按钮在同一行的控件,即删除控件所在的行。如果我只删除特定的文本框和组合框控件,则会从面板中删除所有控件,但我只想删除与删除按钮在同一行的控件。 - shariq_khan
1
@shariq_khan,我会告诉你,但对于你来说可能很难跟上,因为你对这一切还很陌生。但是我告诉你,一旦你明白了正在发生的事情,这其实非常非常容易。当您在动态添加控件到表单时,需要对它们进行某些引用,但您可能没有该引用。因此,您需要将每个动态创建的控件标记为已知对象。在这种情况下,您的按钮是一个您将在要删除行时访问的对象。因此,最好将每个控件对象“标记”到该特定行的相应“按钮”。 - nawfal
1
稍后当您点击按钮时,事件处理程序将具有一个“sender”参数,该参数提供有关调用处理程序的控件的信息。因此,在这种情况下,“sender”就是您的清除按钮本身。现在,我们将循环遍历所有控件,并查看它们的“Tag”属性是否为我们的“sender”按钮。只有那些按钮行的控件才会将它们的“Tag”设置为“sender”按钮。因此,您可以删除它们,包括按钮本身。 - nawfal
先生,请在这里帮帮我。 http://stackoverflow.com/questions/14302330/changing-the-current-cell-selection-of-datagridview-to-row-select - shariq_khan
1
对于你的第一和第二个解决方案,修改正在枚举的基础集合不是不切实际吗? - user3260977
显示剩余6条评论

5
如果您有一个带有动态组件的面板或其他容器,要删除所有或多个组件,可以按照以下步骤进行操作。
第一步,将组件加载到数组或列表中。
List<PersonalUserControl> lst = new List<PersonalUserControl>();

foreach (Object obj in this.PanelImplementationTeam.Controls)
{     
    //DO NOT REMOVE COMPONENT IN THIS LOOP BECAUSE
    //YOU DECREASE THE .Controls  ARRAY AND YOU WILL HAVE AN ERROR      
    if (obj is PersonalUserControl)
    {
        lst.Add((PersonalUserControl)obj);
    }
}

foreach(PersonalUserControl uc in lst)
{
    uc.Dispose();
}

2
如果您想删除的所有控件都在一个面板中,您可以这样做:panel.Controls.Clear(); 这会清除您的面板中的所有控件。

0

移除控件事件。来自MSDN

通过编程方式从集合中移除控件

  1. 从事件中移除事件处理程序。在Visual Basic中,使用RemoveHandler语句关键字;在Visual C#中,使用-=运算符(C#参考)
  2. 使用Remove方法从面板的Controls集合中删除所需的控件。
  3. 调用Dispose方法释放控件使用的所有资源。

链接页面中提供了使用VB和C#的具体示例。


这相当于把某人扔给狼群。您也不必删除事件处理程序并调用dispose来删除对象,尽管这可能是最佳实践。但是MSDN有一些糟糕的示例,因此OP提出了问题。此外,他不仅要尝试删除一个控件,而且还要在单击事件期间删除一行控件。因此,您的#2是唯一适用的,并且您方便地省略了该代码以进行协助。 - vapcguy

0

你可以通过使用Find方法加上Remove方法来删除它。

1.首先,你需要为生成的一组TextBox或按钮创建一个唯一的标识(比如相同的名称或其他),然后你可以使用以下代码点击“删除按钮”来删除它们。在循环中运行此代码以一次性删除所有。

Controls.Remove(Controls.Find("唯一标识", true).LastOrDefault());

我尝试创建了许多按钮,并从最后一个开始删除。希望这对你有所帮助。

2.不要忘记从你的集合中也将其删除,可以通过查找并移除最后一个来实现。

yourCollection.RemoveAt(yourCollection.Count - 1);


同样重要的是取消订阅事件处理程序并释放被移除的控件。否则,这将导致一个泄漏,可能或可能不会最终由第二代垃圾回收处理。 - dodexahedron
没错,我已经把它加入解决方案中了 :) - Jirka Kaja

0

由于控件是在运行时添加的,因此在使用findName方法之前,请使用register方法进行注册。

StackPanel sp = new StackPanel
{
   Name = "mySP",
   Orientation = Orientation.Horizontal,
};

//need to register the control to find it by name
RegisterName(sp.Name, sp);

//now to find control by name 
StackPanel sp = (StackPanel)mainStackPanel.FindName("mySP");

//deleting the control found
mainStackPanel.Children.Remove(sp);

//if you need to use the same name again, you have to unregister too
UnregisterName(sp.Name);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接