【问题标题】:How do I get all controls of a form in Windows Forms?如何在 Windows 窗体中获取窗体的所有控件?
【发布时间】:2011-02-13 16:17:57
【问题描述】:

我有一个名为AForm

A 包含许多不同的控件,包括一个主要的GroupBox。这个GroupBox 包含很多表格和其他GroupBoxes。我想找到一个控件,例如A 表单中的标签索引 9,但我不知道哪个 GroupBox 包含此控件。

我该怎么做?

【问题讨论】:

标签: c# winforms forms


【解决方案1】:

使用递归...

public static IEnumerable<T> Descendants<T>( this Control control ) where T : class
{
    foreach (Control child in control.Controls) {

        T childOfT = child as T;
        if (childOfT != null) {
            yield return (T)childOfT;
        }

        if (child.HasChildren) {
            foreach (T descendant in Descendants<T>(child)) {
                yield return descendant;
            }
        }
    }
}

你可以像这样使用上面的函数:

var checkBox = (from c in myForm.Descendants<CheckBox>()
                where c.TabIndex == 9
                select c).FirstOrDefault();

这将获得表单内任何位置的第一个 CheckBox,其 TabIndex 为 9。显然,您可以使用任何您想要的标准。

如果你不喜欢LINQ 查询语法,上面可以重写为:

var checkBox = myForm.Descendants<CheckBox>()
                     .FirstOrDefault(x=>x.TabIndex==9);

【讨论】:

  • 哇,这是一种极端的、过于复杂的方法来找到一个标签索引为 9 的控件。不过感谢您的努力。
  • 您的方法只能找到选项卡索引为 9 的控件。我的方法是有效启用 LINQ to WinForms 的扩展方法。这与 LINQ to XML 使用的方法相同。它并不复杂,它像许多其他答案一样简单递归。唯一的区别是我过滤了类型,这使得谓词更容易编写。
  • +1 用于检查类型和收益返回也将确保不再评估需要评估的控件。也可以很容易地应用于许多其他条件,而无需修改扩展方法,并且还可以检查特定于类型的属性(如IsChecked)! @Ed Swangren 如果您不想再查看 TabIndex 怎么办?查询(或谓词)不是一个坏主意。
  • @Ed:当在不久的将来需要找到一个没有子控件的控件时,就会出现这种解决方案的优雅之处。您可以重用代码,只需通过不同的比较来调用它,而不是为该新案例使用几乎相同的新方法扩展代码库。
  • @EdS。祝你好运,总是写一段不同的代码,只做当天需要的事情。使用 Josh 的代码,您只需编写一次,仅测试一次,然后在需要在任何表单上找到任何控件时使用它。
【解决方案2】:

递归搜索表单的 Controls 集合。

void FindAndSayHi(Control control)
{
    foreach (Control c in control.Controls)
    {
        Find(c.Controls);
        if (c.TabIndex == 9)
        {
            MessageBox.Show("Hi");
        }
    }
}

【讨论】:

    【解决方案3】:

    你可以做一个这样的方法:

    public static Control GetControl(Control.ControlCollection controlCollection, Predicate<Control> match)
    {
        foreach (Control control in controlCollection)
        {
            if (match(control))
            {
                return control;
            }
    
            if (control.Controls.Count > 0)
            {
                Control result = GetControl(control.Controls, match);
                if (result != null)
                {
                    return result;
                }
            }
        }
    
        return null;
    }
    

    ...这样使用:

    Control control = GetControl(this.Controls, ctl => ctl.TabIndex == 9);
    

    但请注意,TabIndex 是一个棘手的情况,因为它在每个容器中从 0 开始,因此可能有多个相同形式的控件具有相同的 TabIndex 值。

    无论哪种方式,上面的方法都可以用来检查控件的几乎所有属性:

    Control control = GetControl(this.Controls, ctl => ctl.Text == "Some text");
    

    【讨论】:

      【解决方案4】:
      void iterateControls(Control ctrl)
      {
          foreach(Control c in ctrl.Controls)
          {
              iterateControls(c);
          }
      }
      

      【讨论】:

        【解决方案5】:

        我讨厌递归,所以我总是使用堆栈来处理这类事情。这会为当前控件层次结构中每个 RadioButton 控件的 CheckedChanged 事件分配一个公共事件处理程序:

        Stack<Control> controlStack = new Stack<Control>();
        foreach (Control c in this.Controls)
        {
            controlStack.Push(c);
        }
        Control ctl;
        while (controlStack.Count > 0 && (ctl = controlStack.Pop()) != null)
        {
            if (ctl is RadioButton)
            {
                (ctl as RadioButton).CheckedChanged += new EventHandler(rb_CheckedChanged);
            }
            foreach (Control child in ctl.Controls)
            {
                controlStack.Push(child);
            }
        }
        

        您可以轻松地改造 Josh Einstein 的扩展方法使其以这种方式工作。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-06-30
          • 2017-10-18
          • 2013-12-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多