15

我知道如何查找和收集 Windows 窗体中使用的所有控件的列表。像这样的东西:

static public void FillControls(Control control, List<Control> AllControls)
{
    String controlName = "";
    controlName = control.Name;

    foreach (Control c in control.Controls)
    {
        controlName = c.Name;
        if ((control.Controls.Count > 0))
        {
            AllControls.Add(c);
            FillControls(c, AllControls);
        }
    }
}

但是,此函数不会检索表单底部的非可视组件,如 HelpProvider、ImageList、TableAdapters、DataSets 等。

有没有办法获取这些组件的列表?

编辑:

感谢@HighCore 指出我在类似的函数中使用 System.ComponentModel.Component 确实为我提供了一个包含 ImageList、Help Provider 和 BindingSource 等组件的列表。但是,我仍然从这个列表中错过了 TableAdapters 和 DataSets。我想是因为那些直接继承自 Object。

。不要让我参考显示与我的功能相似且仅获取控件列表的旧帖子。

编辑:为什么反对票?这个问题以前从来没有回答过!

4

2 回答 2

16

令人惊讶的是,似乎唯一的方法是通过反射。

private IEnumerable<Component> EnumerateComponents()
{
    return from field in GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
           where typeof (Component).IsAssignableFrom(field.FieldType)
           let component = (Component) field.GetValue(this)
           where component != null
           select component;
}
于 2013-06-18T15:47:29.473 回答
1

通过设计器构建的所有控件都必须有一个名为“组件”的 IContainer 类型的私有字段。您可以使用反射来获取该字段的值(如果存在),然后遍历组件。

此方法与其他答案的不同之处在于,它只会返回使用设计器添加到表单的组件,而不是可以转换为组件的所有字段。

    public IEnumerable<Component> GetComponents(Control c)
    {
        FieldInfo fi = c.GetType()
            .GetField("components", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
        if (fi?.GetValue(c) is IContainer container)
        {
            return container.Components.OfType<Component>();
        }
        else
        {
            return Enumerable.Empty<Component>();
        }
    }
于 2019-07-25T04:49:59.713 回答