1

I would like to retrieve all components which are part of a Form's or UserControl's components collection. The components collection is added by VS winforms designer. The components variable is private and the problem is how to retrieve all components from all descendants. I would like to have a method which returns list of components throught the type hierarchy. For example let's say I have MyForm (descendant of BaseForm) and BaseForm (descendant of Form). I would like to put method "GetComponents" which returns components of both MyForm and BaseForm.

Do you suggest any other option than using the reflection?

Zvonko
  • 363
  • 2
  • 19
  • checkout [this answer](http://stackoverflow.com/a/371829/1495442) – Ria Aug 13 '12 at 09:40
  • This doesn't work at runtime. What I want to achieve is to have one method in my base class which returns list of all components found in all subclasses. – Zvonko Aug 13 '12 at 11:45
  • Did you try iterating through the Control.Controls collection? You can write a simple recursive function that takes a parent control (e.g. your form) as input and then loops through its controls collection. I ofte use this technique to programmatically attach/detach an event handler to/from every component in a form. – Edenbauer Aug 13 '12 at 16:05
  • Of course I did. :) However, in the Controls collection components are not present. Controls collection contains only those components which have user interface (inherited from System.Windows.Forms.Control). Components which inherit from System.Windows.Forms.Component (for example, Timer) do not have user interface and thus are not in the Controls collection. – Zvonko Aug 14 '12 at 17:06
  • Interesting problem :) I don't have access to VS right now but let's think it through. _components_ is just a private field for the control, so all controls in the hierarchy have access to their respective components. Have you tried adding a _virtual method_ in the base form and override it throughout the hierarchy to add the components to a list? Something like that, is that even possible? :) I'll take a look once I get home and am able to play with it – Albin Dec 18 '12 at 10:33
  • I would suggest having common interface, which your base form and base control implements, returning (filed, enumerator of controls, etc) of private field **components**, where it is used. And then iterating through hierarchy. – Algirdas Dec 20 '12 at 11:56

1 Answers1

3

Some time ago I have implemented the solution in which I created custom base form and control implementations, adding one property and overriding the OnLoad method:

public partial class FormBase : Form   
{
    public FormBase ()
    {
        this.InitializeComponent();
    }

    protected ConsistencyManager ConsistencyManager { get; private set; }

    protected override void OnLoad(System.EventArgs e)
    {
        base.OnLoad(e);

        if (this.ConsistencyManager == null)
        {
            this.ConsistencyManager = new ConsistencyManager(this);
            this.ConsistencyManager.MakeConsistent();
        }
    }
}

The ConsistencyManager class finds all controls, components and also supports search of custom child controls within specific control. Copy/paste of code from MakeConsistent method:

    public void MakeConsistent()
    {
        if (this.components == null)
        {
            List<IComponent> additionalComponents = new List<IComponent>();

            // get all controls, including the current one 
            this.components =
                this.GetAllControls(this.parentControl)
                .Concat(GetAllComponents(this.parentControl))
                .Concat(new Control[] { this.parentControl });

            // now find additional components, which are not present neither in Controls collection nor in components
            foreach (var component in this.components)
            {
                IAdditionalComponentsProvider provider = GetAdditinalComponentsProvider(component.GetType().FullName);

                if (provider != null)
                {
                    additionalComponents.AddRange(provider.GetChildComponents(component));
                }
            }

            if (additionalComponents.Count > 0)
            {
                this.components = this.components.Concat(additionalComponents);
            }
        }

        this.MakeConsistent(this.components);
    }

If anyone would like full sample or source let me know.

Best regards, Zvonko

PS: In the same manner I have also created the performance counter that counts number of invocations on main thread.

Zvonko
  • 363
  • 2
  • 19