【问题标题】:How can I dispose of dynamically created controls?如何处理动态创建的控件?
【发布时间】:2014-06-03 18:26:25
【问题描述】:

我在 TabPages 上动态创建控件,当然,这些控件位于 TabControl 上。我也希望能够动态处理这些。我怎样才能做到这一点?在 TabControl 的 TabPages 集合上调用 Clear 实际上会释放 TabPages 本身,这违背了在这些页面上使用新的动态创建的控件“重新开始”的目的。

调用 tabPageBla.Controls.Clear() 与我想要的很接近,但它也会在我需要保留的每个 TabPage (FlowControlLayout) 上配置一个容器控件。

有没有一种简单的方法来实现这一点(只处理动态创建的控件,而不是其他任何控件)?

更新

这项工作是否可行 - 是否还会找到 TabControl1 的孙子(标签页的子页)?:

List<Control> ctrls = new List<Control>();
ctrls.AddRange(tabControl1.Controls);
foreach (var ctrl in ctrls)
{
    // Controls named "panelRowBla", "richTextBoxBla", and "pictureBoxBla" need to be retained
    string ctrlName = ctrl.Name;
    if ((ctrlName.Contains("panelRow")) ||
        (ctrlName.Contains("richTextBox")) ||
        (ctrlName.Contains("pictureBox")))
    {
        continue;
    }
}

更新 2

这很奇怪;我可以发誓这只是编译,但现在我得到“Argument 1: cannot convert from 'System.Windows.Forms.Control.ControlCollection' to System.Collections.Generic.IEnumerable'

(在“AddRange()”行)。

【问题讨论】:

  • 抱歉 - 添加了“Winforms”标签。

标签: c# winforms dynamic dispose


【解决方案1】:

如果你从父级移除控件,你可以显式地Dispose它,即:

 parent.Controls.Remove(theControl);
 ((IDisposable)theControl).Dispose();

鉴于您的编辑,您应该能够做到:

var toRemove = tabControls1
      .Controls
      .Cast<Control>()
      .Where(c => !(c.Name.Contains("panelRow") || c.Name.Contains("richTextBox") || c.Name.Contains("pictureBox")))
      .ToList();

foreach(var c in toRemove)
{
     tabControls1.Controls.Remove(c);
     ((IDisposable)c).Dispose();
}

这将从tabControl1 中删除与您的过滤器不匹配的所有控件。

【讨论】:

  • 不过,我需要一种方法来遍历它们,因为它们可能存在 googleplex。
  • @B.ClayShannon 只需在parent.Controls(即:var toRemove = parent.Controls.ToList();)中保留控件的本地副本并删除每个。
  • 作为一个有趣的旁注;使用今天的当前系统,您将得到一个 OutOfMemoryException 试图实例化一个 googleplex 控件:P
  • @ErikPhilips:很有可能;在个人层面上,我得到了一个 OOME,试图记住我昨天午餐吃了什么。
  • 通过使用Dispose(),将Control从其当前父控件的Control.ControlCollection中移除。
【解决方案2】:

无法判断控件是在设计器中创建的还是动态创建的。但是您可以做的是创建一个包含所有控件的列表,这些控件一开始就存在(在设计器中创建的控件)。

为类的根创建一个新列表,以保存所有“原始”控件:

List<Control> DesignerControls;

使用此修改后的 PsychoCoder 方法 (https://stackoverflow.com/a/3426721/2538037) 列出所有控件(包括控件内的控件):

public IEnumerable<Control> GetAll(Control control)
{
   var controls = control.Controls.Cast<Control>();

   return controls.SelectMany(ctrl => GetAll(ctrl))
                  .Concat(controls);
}

在您动态添加任何控件之前,请运行此行(例如在构造函数中):

DesignerControls = GetAll(this).ToList();

然后添加这个静态方法来处理动态创建的控件:

public static bool DisposeDynamicObjects(List<Control> NonDynamicControls, List<Control> ControlsToDispose)
{
   try
   {
      for (int i = 0; i < ControlsToDispose.Count; i++)
      {
         if (ControlsToDispose[i] != null &&
             !ControlsToDispose[i].IsDisposed &&
             !NonDynamicControls.Contains(ControlsToDispose[i]))
         {
            ControlsToDispose[i].Dispose();
            --i;
         }
      }
      return true;
   }
   catch (Exception ex) { MessageBox.Show(ex.Message); return false; }
}

当你想释放动态创建的控件时,使用这个:

DisposeDynamicObjects(DesignerControls, GetAll(tabControl1).ToList());

上面的代码在tabControl1.Controls 中处理所有动态创建的控件。您可以将tabControl1 替换为其他控件,例如this,这样所有动态创建的控件都会从整个表单中删除。

【讨论】:

  • 谢谢;我将“tabPage1”更改为“tabControl1”(希望这就是您的意思 - 但这似乎是在不将它们从视线中移除的情况下处理控件 - 我是否需要为此调用 Refresh 或类似的方法?
  • 我用一些新代码更新了答案。这是使用它的一种方式。
  • 我更新了DisposeDynamicObjects()-方法的参数类型。请复制并使用这个新版本。还要注意.Cast&lt;Control&gt;().ToList()
  • 您可以使用递归的方法列出控件内的所有控件,包括GroupBoxes及其控件。这是一个链接:kon-phum.com/tutors/pascal/…。你可以这样使用它:DesignerControls = GetAllControls(tabControl1.Controls);。当您不想处理对象时,请运行Form1.DisposeDynamicObjects(DesignerControls, GetAllControls(tabControl1.Controls));。我还没有测试过该链接的方法,但它应该可以工作。
  • 我重写了答案以使其更加通用。我也很快对其进行了测试,它确实有效。
猜你喜欢
  • 2010-11-09
  • 1970-01-01
  • 1970-01-01
  • 2011-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多