Enumerating non-ui components from the given form instance

Y

Yasutaka Ito

Hi,

As you know, all the non-ui components (like Timer control, etc.) that sit
on the form are contained in its private variable 'components'.

How can I enumerate such components from any form instance given to me? I
have no access to the source of the given form instance, but I can impose
that the form be inherited from certain base class I provide.

Would appreciate any inputs. If there is other way to access the non-ui
components (other than using the 'components' variable), would appreciate to
hear that.

thanks!
-Yasutaka
 
Y

Yasutaka Ito

Thanks Dinesh. This will work if you're searching it within the same form,
but
what I want is an instance of form that's given to me.

For example, I have a routine like this...

public void EnumerateComponents(System.Windows.Forms.Form anyFormInstance)
{
foreach (System.ComponentMode.Component component In
anyFormInstance.components)
{
System.Diagnostics.Debugs.WriteLine(component.ToString());
}
}

But, this routine will not work, as the 'components' is private variable of
the
anyFormInstance. I have no access to the source code of the anyFormInstance.
At the most, I can creator a base form, which I can impose to the author of
the
Form (that's passed to the anyFormInstance parameter) to inherit from.

It'd be too bad if I can't have an access to the components... do you think
Reflection has something in store? I don't have much idea bout this form...

thanks!
-Yasutaka
 
Y

Yasutaka Ito

Thanks Iulian!
I tried this, but this always return me null. :( I'm trying the following.

1) I have Form1 with a button
2. In the button's Click() event, I'm calling my EnumerateComponents
function passing the instance of Form2.

private void button1_Click(object sender, System.EventArgs e)
{
Form2 form = new Form2();
ComponentsCollection(form);
}

public void EnumerateCollection(System.Windows.Forms.Form anyFormInstance)
{
foreach(System.ComponentModel.Component component in
anyFormInstance.Site.Container.Components)
{
MessageBox.Show(component.ToString());
}
}

I must be getting something screwed up here... would appreciate any help.

thanks!
-Yasutaka

Iulian Ionescu said:
Read the Site of a control that exists on the form or of the form itself.
Check the Container member of the Site and it will contain a list of
available components. If you need the type of the components you will need a
reference to a IReferenceService (get it using Site.GetSevice) and use its
methods to make the query...
 
S

Stoitcho Goutsev \(100\) [C# MVP]

Hi Yasutaka,
I wrote a simple iterator class for you. You can use it to get the
compontets your controls host. You may use the code as is, but bare in mind
that it will work only for the controls generated with VS wizard because it
looks for the *components* member. And of course if you want to use it as is
I'll suggest you do do some more testing because I haven't done enough. The
code is at the end of this post.

You can use the class like this

foreach( Component c in new ComponentsIterator(control, false))
{
....
}

If the secont constructor's parameter is *false* the interator will
iterates only over the components from the controls' class
If true it will iterate over the parent classes as well.


The class:
===========

using System;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Reflection;

namespace Iterator
{
/// <summary>
/// Summary description for ComponentsEnumerator.
/// </summary>
public class ComponentsIterator: IEnumerable, IEnumerator
{
private Control mTarget;
private IEnumerator mCurrentEnumerator;
private bool mInherited;
private FieldInfo mComponentsField = null;
public ComponentsIterator(Control ctrl, bool inherited)
{
mTarget = ctrl;
mInherited = inherited;
Reset();
}

private void InitializeEnumerator()
{
mCurrentEnumerator = null;
if(mComponentsField != null)
{
IContainer components = mComponentsField.GetValue(mTarget) as
IContainer;
if(components != null)
{
mCurrentEnumerator = components.Components.GetEnumerator();
}
}
}
#region IEnumerable Members

public IEnumerator GetEnumerator()
{
return this;
}

#endregion

#region IEnumerator Members

public void Reset()
{
mComponentsField = mTarget.GetType().GetField("components",
BindingFlags.NonPublic | BindingFlags.Instance);
InitializeEnumerator();

}

public object Current
{
get
{

if(mCurrentEnumerator == null) throw new InvalidOperationException();
return mCurrentEnumerator.Current;
}
}

public bool MoveNext()
{
if(mCurrentEnumerator == null) throw new InvalidOperationException();
bool res = mCurrentEnumerator.MoveNext();
while(!res && mCurrentEnumerator != null)
{
if(mInherited)
{
mComponentsField =
mComponentsField.DeclaringType.BaseType.GetField("components",
BindingFlags.NonPublic | BindingFlags.Instance);
InitializeEnumerator();
if(mCurrentEnumerator != null) res = mCurrentEnumerator.MoveNext();
}
else break;


}
return res;
}

#endregion
}
}
 
Y

Yasutaka Ito

Hey, thanks a lot for that... I have done in a similar manner. Here is what
I ended
up with. I'm using GetField(), as I know that it is a field, and I'm taking
the default
field name 'components', to make the search simple and faster.

// myForm is an instance of System.Windows.Forms.Form
FieldInfo fieldInfo = myForm.GetType().GetField("components",
BindingFlags.NonPublic |
BindingFlags.Instance);

if (fieldInfo != null)
{
System.ComponentModel.IContainer components =
(System.ComponentModel.IContainer)fieldInfo.GetValue(myForm);
if (components != null)
{
return components;
}
}
return null;

thanks to all for the help.
-Yasutaka
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top