简体   繁体   中英

Find components on a windows form c# (not controls)

I know how to find and collect a list of all the controls used in a Windows Form. Something like this:

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

However this function does not retrieve the non-visual components on the bottom of the form like the HelpProvider, ImageList, TableAdapters, DataSets, etc.

Is there a way to get the list of these components as well?

Edit:

Thanks @HighCore for pointing me to use System.ComponentModel.Component instead in a similar function does get me a list with components such the ImageList, the Help Provider and the BindingSource. However, I still miss from this list the TableAdapters and the DataSets. I suppose because those inherit directly from Object.

Please . Don't refer me to older posts which shows a similar function to mine and that only gets the list of the controls.

Edit: Why the negative votes? This question has never been answered before!

Surprisingly, it seems the only way to do this is via reflection.

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

All controls built through the designer must have a private field called "components" of type IContainer. You can use reflection to get the value of this field, if it exists, and then iterate through the components.

This method differs from the other answer in that this will only return the components added to the form using the designer, as opposed to all fields that can be cast as 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>();
        }
    }

There is a cleaner way than Reflection to get components from a form. The form itself is a component holder, so it is good that it implements IContainer, as such, I don't even understand why it wasn't done that way.

After casting it into an IContainer, not only will you be able to retrieve all the components generated by the designer, but as a bonus, you will also be able to add/remove your own components, obeying the Form Dispose() mechanism.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM