获取特定类型的所有控件

49

我有多个图片框,需要在运行时随机加载图像。因此,我认为拥有所有图片框的集合,然后使用简单循环为它们分配图像会很不错。但是我该如何做呢?或者说是否有更好的解决方案?

9个回答

92

使用 LINQ:

foreach(var pb in this.Controls.OfType<PictureBox>())
{
  //do stuff
}

然而,这只会处理主容器中的PictureBox。


24
这不会考虑嵌套在其他容器中的PictureBoxes。 - cdhowie
1
另外一种方法是使用foreach循环遍历所有PictureBox控件:foreach(PictureBox pb in this.Controls.OfType<PictureBox>()) { //执行操作 }虽然可能没有太大区别,但我更喜欢显式声明。 - Scooter
对于像这样的问题,您有什么看法:https://stackoverflow.com/questions/47182809/how-to-count-the-checkboxes-in-a-asp-net-form/47182982#47182982 - Si8

29
您可以使用以下方法:

您可以使用此方法:

public static IEnumerable<T> GetControlsOfType<T>(Control root)
    where T : Control
{
    var t = root as T;
    if (t != null)
        yield return t;

    var container = root as ContainerControl;
    if (container != null)
        foreach (Control c in container.Controls)
            foreach (var i in GetControlsOfType<T>(c))
                yield return i;
}

那么你可以做这样的事情:
foreach (var pictureBox in GetControlsOfType<PictureBox>(theForm)) {
    // ...
}

1
我认为这比仅使用 root.Controls.OfType<T> 更啰嗦。 - Dan Tao
6
哦,我明白了,你让它无限深度。收到。 - Dan Tao
@cdhowie 在哪里插入OfType<T>()才是正确的呢?在最终搜索的末尾(链接中的第二段代码)而不是初始搜索中,这样对吗? - tedebus
考虑无限序列的生成器,例如正整数、质数或斐波那契序列。这些可枚举对象无法存储整个结果序列,因为该序列是无限的。相反,它们每次枚举器前进时产生一个项目。这正是这里发生的事情:枚举器逐个生成一个控件,并在枚举期间应用过滤器(例如OfType<T>())。 - cdhowie
2
一年后... 当项目位于作为父容器的 Group Box 的子级的情况下,这种方法无法奏效。显然它们不是 ContainerControl?太疯狂了。 - Ronnie W
显示剩余9条评论

9

如果您的 .NET 版本至少为 3.5,则可以使用 LINQ。由于 ControlCollection 实现了 IEnumerable,因此您只需执行以下操作:

var pictureBoxes = Controls.OfType<PictureBox>();

3
这不会考虑嵌套在其他容器中的PictureBox。 - cdhowie
2
好的。为自己辩护,楼主并没有明确说明那是一个要求;但是,将其视为要求可能会更有意义。 - Dan Tao

5
一个简单易懂的函数,递归调用,可以在任何表单控件中调用:
private void findControlsOfType(Type type, Control.ControlCollection formControls, ref List<Control> controls)
    {
        foreach (Control control in formControls)
        {
            if (control.GetType() == type)
                controls.Add(control);
            if (control.Controls.Count > 0)
                findControlsOfType(type, control.Controls, ref controls);
        }
    }

您可以以多种方式调用它。要获取按钮,请使用以下方法:
List<Control> buttons = new List<Control>();
findControlsOfType(typeof(Button), this.Controls, ref buttons);

获取面板的方式如下:
List<Control> panels = new List<Control>();
findControlsOfType(typeof(Panel), this.Controls, ref panels);

etc.


这对我非常有效,我只是稍微修改了if语句:if (control.GetType() == type || control.GetType().IsSubclassOf(type)) - blind Skwirl

5

我使用这个通用的递归方法:

这种方法的假设是,如果控件是 T 类型,则该方法不会查找其子元素。如果您还需要查看其子元素,可以轻松更改它。

public static IList<T> GetAllControlsRecusrvive<T>(Control control) where T :Control 
{
    var rtn = new List<T>();
    foreach (Control item in control.Controls)
    {
        var ctr = item as T;
        if (ctr!=null)
        {
            rtn.Add(ctr);
        }
        else
        {
            rtn.AddRange(GetAllControlsRecusrvive<T>(item));
        }

    }
    return rtn;
}

3

由于现有提供的版本并不完全符合我的想法,这里提供另一种版本。这个版本可以作为一个扩展方法,可选地排除检查根/父容器的类型。该方法基本上是一个“获取所有类型为 T 的后代控件”的方法:

public static System.Collections.Generic.IEnumerable<T> ControlsOfType<T>(this System.Web.UI.Control control) where T: System.Web.UI.Control{
    foreach(System.Web.UI.Control childControl in control.Controls){
        if(childControl is T) yield return (T)childControl;
        foreach(var furtherDescendantControl in childControl.ControlsOfType<T>()) yield return furtherDescendantControl;
    }
}

1

对我来说,这是最简单的。在我的应用程序中,我试图清除面板中的所有文本框:

    foreach (Control c in panel.Controls)
    {
        if (c.GetType().Name == "TextBox")
        {
            c.Text = "";
        }
    }

我刚刚意识到在我发布这个答案之后,它本质上与Zelkovar的答案相同。 - Richard Martin

1
    public static List<T> FindControlByType<T>(Control mainControl,bool getAllChild = false) where T :Control
    {
        List<T> lt = new List<T>();
        for (int i = 0; i < mainControl.Controls.Count; i++)
        {
            if (mainControl.Controls[i] is T) lt.Add((T)mainControl.Controls[i]);
            if (getAllChild) lt.AddRange(FindControlByType<T>(mainControl.Controls[i], getAllChild));
        }
        return lt;
    }

0

考虑容器控制:

        private static IEnumerable<T> GetControlsOfType<T>(this Control root)
        where T : Control
    {
        if (root is T t)
            yield return t;

        if (root is ContainerControl || root is Control)
        {
            var container = root as Control;
            foreach (Control c in container.Controls)
                foreach (var i in GetControlsOfType<T>(c))
                    yield return i;
        }
    }

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