winforms 查找Windows窗体上的组件C#(而不是控件)

am46iovg  于 2023-02-05  发布在  Windows
关注(0)|答案(3)|浏览(262)

我知道如何查找和收集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、DataSet等。
是否也有方法获得这些组件的列表?

    • 编辑:**

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

    • 请**。不要让我参考旧的帖子,这些帖子显示了与我类似的功能,而且只得到了控件列表。
    • 编辑:**为什么是反对票?这个问题以前从来没有得到过回答!
ruyhziif

ruyhziif1#

有一种比Reflection更干净的方法可以从表单中获取组件。表单本身就是一个组件保持器,所以它实现IContainer是件好事,就像这样,我甚至不明白为什么不这样做。
在将它转换为IContainer之后,您不仅能够检索设计器生成的所有组件,而且还能够添加/删除自己的组件,这是一个额外的好处,它遵循Form Dispose()机制。

public partial class MyForm : Form, IContainer
{

    // ...

    public void Add(IComponent component) => this.components.Add(component);

    public void Add(IComponent component, string name) => this.components.Add(component, name);

    public void Remove(IComponent component) => this.components.Remove(component);

    public ComponentCollection Components => components.Components;
}
4dc9hkyq

4dc9hkyq2#

令人惊讶的是,似乎只有通过反射才能做到这一点。

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;
}
0x6upsns

0x6upsns3#

通过设计器生成的所有控件都必须具有称为“components”的IContainer类型的私有字段。如果此字段存在,则可以使用反射获取该字段的值,然后循环访问这些组件。
此方法与另一个答案的不同之处在于,它将仅返回使用设计器添加到窗体中的组件,而不是可以强制转换为Component的所有字段。

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>();
        }
    }

相关问题