Forms' LifeCycle - Inheritance

M

Michael Maes

Hello,

I have a BaseForm with (eg) one Timer in the Components'collection & one Button in the Controls'Collection
Also there are three Subs: Load, ScanControls & ScanComponents.
The BaseForm is only used to be inherited from (and inherits from System.Windows.Forms.Form).
Private Sub BaseForm_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load

ScanControls()

ScanComponents()

End Sub

Private Sub ScanControls()

Dim [Control] As System.Windows.Forms.Control

For Each [Control] In Me.Controls

' Scan recursive through the ControlCollection

' Put in HashTableControls

' Do some stuff

Next

End Sub



Private Sub ScanComponents()

Dim [Component] As System.ComponentModel.Component

For Each [Component] In Me.components.Components

' Put in HashTableComponents

' Do some stuff

Next

End Sub


I have Another Form (eg: DisplayForm) which inherits from the BaseForm.
It adds (eg) a Label & a ImageList.

a.. If I look at the ControlsCollection (HashTableControls) I "find" a Button & a Label (Which is correct)
b.. If I look at the ComponentsCollection (HashTableComponents) I only "find" a Timer (Which is wrong: it should also contain the ImageList)
What is wrong with this approach?

TIA,

Michael
 
M

Michael Maes

Hi Charlie,

The components are added in design-time (to the derived form).
They are on the Inherited form
The code is called not in the contructor (sub = private - HashTable =
Public) but in the BaseForm (DLL)

Note: I've added the "BaseForm.vb" in the "Main-Project" to be able to
select it in the inheritance-picker (I haven't found how to display the
'baseform.dll' in the inheritance-picker without this "BaseForm.vb"

so I have:

° System.Windows.Forms.Form
° Added (a lot of) Properties, Events, Methods, ...
° Compiled to a Class (baseform.dll)

° A "Main-Project"
° Referenced baseform.dll
° Created a BaseForm.vb (Inherits from baseform.dll)
° All forms of the main project inherit from that BaseForm.vb

The funny thing is that this works perfect with all (types of) Controls, but
(for one reason or the other) NOT with Components.

It seems like for the Components the collection is Created for the BaseForm
(with the actual Controls on that BaseForm) and one for the Derived Form
(With the Components added in design-time).

Regards,

Michael

PS: I use vs.NET 2003 Ent. Arch.
 
J

Jeffrey Tan[MSFT]

Hi Michael,

Based on my understanding, you loop through the Control collection and
component collection in your BaseForm constructor. When you are using your
inherited form DisplayForm, you find that the BaseForm can loop all the
control collection(even the control of DisplayForm), but it can not find
the components of DisplayForm.

==============================
Actually, this is an expected behavior. Let me explain it to you.

In your BaseForm, you loop through your control collection like this:
Private Sub ScanControls()
Dim [Control] As System.Windows.Forms.Control
For Each [Control] In Me.Controls
.......
Next
End Sub

The "Controls" is a property of BaseForm class, while DisplayForm did not
override this property, so BaseForm and DisplayForm will share the same
property. That is: the Controls property in DisplayForm is the same one of
BaseForm.
So in DisplayForm, when you drag Label onto the form, the Label will be
added into the "Controls", then when visit in parent form(BaseForm), it can
get the Label control.

While for component collection, it is referred in form's private variable
"components". Child form(DisplayForm) and parent form(BaseForm) each has a
"components" of their own. They did not share one copy.
So when you drag ImageList to the Child form(DisplayForm), only
DisplayForm's components variable was changed. While the BaseForm
ScanComponents method will loop through BaseForm's components variable. It
can not see the ImageList.

Hope I have clarified it.
==================================
Thank you for your patience and cooperation. If you have any questions or
concerns, please feel free to post it in the group. I am standing by to be
of assistance.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
M

Michael Maes

Hi Jeffrey,
Thanks for the clarification (and your time).
This is 'extremely' clear.

Regards,

Michael

PS: Maybe I could try something like

Friend SharedComponents As System.ComponentModel.IContainer

In the baseform and add the 'components.Components' after initialization
(but thats just a rough idea...)
 
J

Jeffrey Tan[MSFT]

Hi Michael,

I will spend some time try to find a better workaround for you. I will
reply to you ASAP.

Thanks for your understanding.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
M

Michael Maes

Hi Jeffrey,

That would be most kind of you, because I allready 'noticed' it's not "that
evident".

Regards,

Michael
 
J

Jeffrey Tan[MSFT]

Hi Michael,

Sorry for letting you wait for so long time.

I think it is not a good idea to increase the accessibility of the private
components variable. I think it is a better workaround to expose this
private variable as a virtual property, then you can override this property
in child class. Do like this:

In BaseForm, create a virtual property
public virtual System.ComponentModel.IContainer Components
{
get
{
return this.components;
}
}

In child form override it, and add the child form's components
public override IContainer Components
{
get
{
IContainer ic=base.Components;

foreach(Component c in this.components.Components)
{
ic.Add(c);
}
return ic;
}
}

Then in baseform, you can use it correctly, like this:
private void Form1_Load(object sender, System.EventArgs e)
{
foreach(Component c in this.Components.Components)
{
Console.WriteLine(c.ToString());
}
}

Also, I want to inform you that not all the components will be added into
the components private variable, for more information, please refer to:
"Windows Form Designer generated code"
http://www.developerfusion.com/show/4369/

================================
Please apply my suggestion above and let me know if it helps resolve your
problem.

Thank you for your patience and cooperation. If you have any questions or
concerns, please feel free to post it in the group. I am standing by to be
of assistance.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
M

Michael Maes

Hi Jeffrey,

Thanks for the tip: it works (with a small 'but'):

In the BaseForm add:
(Since 'components' is already declared Private by windows designer: choose a different name)

Public Overridable ReadOnly Property myComponents() As System.ComponentModel.IContainer
Get
Return Me.components
End Get
End Property

In the Derived Form add:

Public Overrides ReadOnly Property myComponents() As System.ComponentModel.IContainer
Get
Dim ic As System.ComponentModel.IContainer = MyBase.myComponents
Dim c As System.ComponentModel.Component
For Each c In Me.components.Components
ic.Add(c)
Next c
Return ic
End Get
End Property

To address 'all' (possible) components in the Derived Form:

Dim c As System.ComponentModel.Component
For Each c In Me.myComponents.Components
Console.WriteLine(c.ToString())
Next c


Thanks for your help,

Regards,

Michael
 
M

Michael Maes

Hi Jeffrey,

Thanks for the tip: it works (with a small 'but'):

In the BaseForm add:
(Since 'components' is already declared Private by windows designer: choose a different name)

Public Overridable ReadOnly Property myComponents() As System.ComponentModel.IContainer
Get
Return Me.components
End Get
End Property

In the Derived Form add:

Public Overrides ReadOnly Property myComponents() As System.ComponentModel.IContainer
Get
Dim ic As System.ComponentModel.IContainer = MyBase.myComponents
Dim c As System.ComponentModel.Component
For Each c In Me.components.Components
ic.Add(c)
Next c
Return ic
End Get
End Property

To address 'all' (possible) components in the Derived Form:

Dim c As System.ComponentModel.Component
For Each c In Me.myComponents.Components
Console.WriteLine(c.ToString())
Next c


Thanks for your help,

Regards,

Michael
 
J

Jeffrey Tan[MSFT]

Hi Michael,

Thanks very much for your feedback.

I am glad it can help you. :)

Because I am using C#, which is case-sensitive, I can just use Components
as the property

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
M

Michael Maes

Hi Jeffrey,

I didn't know that (Case-Sensitive).
That makes it easy (but maybe sometimes confusing)

I've created a new class of it & added it to the VSDir-Wizard (saves alot of
work)

Thanks,

Michael
 

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