C#动态删除控件,它实际上是做什么的?

时间:2019-01-11 08:42:56

标签: c# winforms

首先,发布帖子,以便我简短回答。

我在标签页中添加了一个控件。由于仅具有一个变量的限制,但是名称属性不同。我决定将我创建的所有文本框对象添加到列表中。文本框是通过循环创建的。

现在,当我删除它们时,我知道我必须调用dispose方法。我必须删除控件,最后减少事件处理程序。

我的问题是这些实际上是做什么的。我希望删除后的文本框列表不再存在。因此,如果我调用其属性(例如名称等),则该列表应为空或抛出异常。

那么为什么这些文本框仍在我的列表中并且仍然起作用?好像我从未删除过它们。尽管它们不再存在于我的表单中,但看起来它们仍然生活在后台,这可能意味着内存泄漏或程序变慢。对于这些方法的作用以及为何文本框对象仍然存在的任何解释,我将不胜感激。

最后一点,我来自cpp。因此,我看到它曾经被动态创建的对象称为Delete的方式,该变量将不再起作用。

此外,如果需要,我可以添加我的代码。

编辑:我的代码如下

  1. 用于添加到标签页:

    if (int.TryParse((sender as TextBox).Text, out int Stories))
    {
    
    
        Console.WriteLine(Stories); this.Stories = Stories;
        string L_name = "Label_";
        string T_name = "TextBox_";
        int counter = 1;
        int yIncr = Story_label.Size.Height + 3;//widthoftextbox+spacing
        List<string> L_name_arr = new List<string>
        {
            L_name + counter.ToString()
        };
        List<string> T_name_arr = new List<string>
        {
            T_name + counter.ToString()
        };
    
        for (int i = 0; i < Stories; i++)
        {
            //create new labels and textboxes below
            //have a max value.
    
            Label L_ = new Label();
            Model_Geometry_tab.Controls.Add(L_);
    
            L_.Location = new System.Drawing.Point(Story_label.Location.X, Story_label.Location.Y + yIncr * counter);//increasing increment every iteration
    
            L_.Name = L_name_arr[i];
            L_.Size = new System.Drawing.Size(Story_label.Size.Width, Story_label.Size.Height);
            L_.Text = "Story" + counter.ToString();
    
            TextBox T_ = new System.Windows.Forms.TextBox();
            //T_.BackColor = System.Drawing.SystemColors.ActiveBorder;
            T_.Location = new System.Drawing.Point(Story_input.Location.X, Story_input.Location.Y + yIncr * counter);
            T_.MaxLength = 1000;
            T_.Name = T_name_arr[i];
            T_.Size = new System.Drawing.Size(Story_input.Size.Width, Story_input.Size.Height);
            T_.KeyDown += new System.Windows.Forms.KeyEventHandler(TextBox_1_KeyDown);
            T_.MouseClick += new System.Windows.Forms.MouseEventHandler(textBox_other_MouseClick);
            T_.MouseHover += new System.EventHandler(textBox2_MouseHover);
            Story_arr.Add(T_);
    
            Model_Geometry_tab.Controls.Add(T_);
    
            //incr counter
            counter++;
            //addnewlabeltags
            L_name_arr.Add(L_name + counter.ToString());
            //addnewtexttags
            T_name_arr.Add(T_name + counter.ToString());
        }
    }
    else
    {
        MessageBox.Show("Enter an integer value please!");
    }
    
  2. 要删除它们,我使用了Story_arr列表;

    private void button2_Click(object sender, EventArgs e)
    {
        if (Story_arr.Count != 0 && !a)
        {
            foreach (var item in Story_arr)
            {
    
                Console.WriteLine(item.Name);
                item.KeyDown -= new System.Windows.Forms.KeyEventHandler(TextBox_1_KeyDown);
                item.MouseClick -= new System.Windows.Forms.MouseEventHandler(textBox_other_MouseClick);
                item.MouseHover -= new System.EventHandler(textBox2_MouseHover);
                Model_Geometry_tab.Controls.Remove(item);
                item.Dispose();
            }
            a = true;
        }
        else if (a)
        {
            foreach (var item in Story_arr)
            {
                Console.WriteLine(item.IsDisposed);
            }
        }
        else
            MessageBox.Show("It is empty list");
    }
    

1 个答案:

答案 0 :(得分:1)

当您调用IDisposable.Dispose时,并不表示该对象已删除。处置对象旨在清除任何内部或外部资源。在WinForms中,这特别意味着要清理所有基础窗口句柄等。

在.NET受管内存中,只有垃圾收集器最终将删除对象。在您的特定情况下,尽管GC永远不会收集您已删除的控件,因为您仍将其保留在列表中。将它们包含在列表中意味着该对象仍被引用,即它们尚未失效。 GC将仅收集死物。

只需手动从列表中删除控件,您就可以了。您还可以监听控件的Disposed事件,并将其从事件处理程序的列表中删除。这样会自动处理从列表中删除所有已处置控件的问题。

更高级的解决方案是不将控件直接添加到列表中,而是添加弱引用。 WeakReference允许您访问对象,但不会阻止垃圾回收。但是,我个人更希望手动取消引用该对象,因为这更直接,而且更不易出错。