Calling a public sub in another form having the name of the form as a string

B

Bugs

Hi,
I wonder if anyone can help me out.

I'm building a vb.net application that has a form with a panel that
contains several other sub forms (as a collection of controls). What
I'm wanting to do is call a generically named public sub in the
top-most sub form in the panel.

I have the name of the top-most form as a string (eg. g_TopForm =
"frmCustomers") and I can reference the form with:

Me.pnlMainWindow.Controls.Item(FormRef)

where the FormRef integer is derived from the function call:

FormRef = FormItemNo(g_TopForm)

and the FormItemNo function is defined as:

Private Function FormItemNo(ByVal formname As String) As Integer
Dim itemref As Integer

Try
'Return impossible number if the form hasn't already been
opened
FormItemNo = 99
For itemref = 0 To Me.pnlMainWindow.Controls.Count - 1
If Me.pnlMainWindow.Controls.Item(itemref).Name =
formname Then FormItemNo = itemref
Next

Catch exp As Exception
MsgBox(exp.Message, MsgBoxStyle.Critical, Me.Text)
End Try
End Function

So, what I'd like to be able to do now is somehow derive a variable
(say subfrm) of type 'frmCustomers' and call:

subfrm.NewRec()

where NewRec() is a public sub in the frmCustomers form class.

Am I barking up completely the wrong tree with this approach or does
anyone have a simple solution to this? I'm not very adept in .net
programming yet (as you may have gathered?!)

Any help is very much appreciated.
Paul
 
C

Chris Chilvers

Hi,
I wonder if anyone can help me out.

I'm building a vb.net application that has a form with a panel that
contains several other sub forms (as a collection of controls). What
I'm wanting to do is call a generically named public sub in the
top-most sub form in the panel.

I have the name of the top-most form as a string (eg. g_TopForm =
"frmCustomers") and I can reference the form with:

Me.pnlMainWindow.Controls.Item(FormRef)

where the FormRef integer is derived from the function call:

FormRef = FormItemNo(g_TopForm)

and the FormItemNo function is defined as:

Private Function FormItemNo(ByVal formname As String) As Integer
Dim itemref As Integer

Try
'Return impossible number if the form hasn't already been
opened
FormItemNo = 99
For itemref = 0 To Me.pnlMainWindow.Controls.Count - 1
If Me.pnlMainWindow.Controls.Item(itemref).Name =
formname Then FormItemNo = itemref
Next

Catch exp As Exception
MsgBox(exp.Message, MsgBoxStyle.Critical, Me.Text)
End Try
End Function

So, what I'd like to be able to do now is somehow derive a variable
(say subfrm) of type 'frmCustomers' and call:

subfrm.NewRec()

where NewRec() is a public sub in the frmCustomers form class.

Am I barking up completely the wrong tree with this approach or does
anyone have a simple solution to this? I'm not very adept in .net
programming yet (as you may have gathered?!)

Any help is very much appreciated.
Paul

When you're creating your sub forms can you not store that top most one
in a member variable?

E.g.

=====================

Public Class MainWindow
Private customers_form As CustomersForm

Public Sub New()
customer_form = new CustomersForm()
End Sub

Public ReadOnly Property TopForm As CustomersForm
Get
return customers_form
End Get
End Property
End Class

=====================

Then you can just call, pnlMainWindow.TopForm.NewRec()
FormItemNo = 99
This would probaly be better as -1. Most zero based arrays use this to
mean 'not found' as it's an index that definitely will not ever be used
as the array begins at zero.


Catch exp As Exception
MsgBox(exp.Message, MsgBoxStyle.Critical, Me.Text)
End Try
You really shouldn't catch all exceptions, as it could be something
critical like, OutOfMemory. If you don't know what the error is then
don't handle it.

If you want to keep the message box there though you could change it to:

Catch exp As Exception
MsgBox(exp.Message, MsgBoxStyle.Critical, Me.Text)

'Throw with no arguments rethrows the current exception
Throw
End Try
 
B

Bugs

Chris said:
When you're creating your sub forms can you not store that top most one
in a member variable?

E.g.

=====================

Public Class MainWindow
Private customers_form As CustomersForm

Public Sub New()
customer_form = new CustomersForm()
End Sub

Public ReadOnly Property TopForm As CustomersForm
Get
return customers_form
End Get
End Property
End Class

=====================

Then you can just call, pnlMainWindow.TopForm.NewRec()

This would probaly be better as -1. Most zero based arrays use this to
mean 'not found' as it's an index that definitely will not ever be used
as the array begins at zero.



You really shouldn't catch all exceptions, as it could be something
critical like, OutOfMemory. If you don't know what the error is then
don't handle it.

If you want to keep the message box there though you could change it to:

Catch exp As Exception
MsgBox(exp.Message, MsgBoxStyle.Critical, Me.Text)

'Throw with no arguments rethrows the current exception
Throw
End Try

Hi Chris,
Huge thanks for your reply! I really appreciate the good advice. I've
taken into account everything you've said and I'm finding the more you
look into this stuff, the more you realise there is to learn!

I can see how your approach will help but how would this work if I
don't know which type of form class my topmost subform is
(unfortunately each of the subforms are of a different form class)?

Since your post, I've found a nifty function - CallByName and have
found this to do the trick in the meantime (albeit not perhaps such a
neat way as you suggested). The call to the subform procedure now looks
like this in the main window code:

CallByName(Me.pnlMainWindow.Controls.Item(FormRef), "NewRec",
CallType.Method)

where FormRef is still derived as originally described in my first post
(by using a string variable to hold the topmost form name).

Whilst this is doing the job for now (and just avoiding knowing the
object's methods at design time), I'd like to ultimately know how to do
this 'properly' if there is a way!

Many thanks for your help!
Paul
 
C

Chris Chilvers

Hi Chris,
Huge thanks for your reply! I really appreciate the good advice. I've
taken into account everything you've said and I'm finding the more you
look into this stuff, the more you realise there is to learn!

I can see how your approach will help but how would this work if I
don't know which type of form class my topmost subform is
(unfortunately each of the subforms are of a different form class)?

Since your post, I've found a nifty function - CallByName and have
found this to do the trick in the meantime (albeit not perhaps such a
neat way as you suggested). The call to the subform procedure now looks
like this in the main window code:

CallByName(Me.pnlMainWindow.Controls.Item(FormRef), "NewRec",
CallType.Method)

where FormRef is still derived as originally described in my first post
(by using a string variable to hold the topmost form name).

Whilst this is doing the job for now (and just avoiding knowing the
object's methods at design time), I'd like to ultimately know how to do
this 'properly' if there is a way!

Many thanks for your help!
Paul

Ah, another good solution is to use an interface. Then each of your sub
forms must implement this interface. In doing so they garuntee that they
will have the methods / properties you specify.

Thus:
=====
Public Interface ISubForm
Public Sub NewRec()
End Interface
=====

Notice how the interface only says this method will exist and not how it
will function.


Now in the class:
=====
Public Class CustomersForm
Implements ISubForm

Public Sub NewRec() Implements ISubForm.NewRec
'Run you code here for creating a new customer record
End Sub
End Class

Public Class SomeOtherForm
Implements ISubForm

Public Sub NewRec() Implements ISubForm.NewRec
'Run you code here for creating a new other record
End Sub
End Class
=====

Both of these class can be considered to be of type ISubForm, thus:
=====
Dim some_form As ISubForm

some_form = New CustomersForm()
some_form.NewRec()

some_form = New SomeOtherForm()
some_form.NewRec()
=====

So now you can change the property to be of type ISubForm instead of
CustomersForm.

Have a look in the help about, when to use interfaces (interfaces, vs.
classes), they can be very helpful as a class can implement more than
one interface as well.
 
B

Bugs

Chris said:
Ah, another good solution is to use an interface. Then each of your sub
forms must implement this interface. In doing so they garuntee that they
will have the methods / properties you specify.

Thus:
=====
Public Interface ISubForm
Public Sub NewRec()
End Interface
=====

Notice how the interface only says this method will exist and not how it
will function.


Now in the class:
=====
Public Class CustomersForm
Implements ISubForm

Public Sub NewRec() Implements ISubForm.NewRec
'Run you code here for creating a new customer record
End Sub
End Class

Public Class SomeOtherForm
Implements ISubForm

Public Sub NewRec() Implements ISubForm.NewRec
'Run you code here for creating a new other record
End Sub
End Class
=====

Both of these class can be considered to be of type ISubForm, thus:
=====
Dim some_form As ISubForm

some_form = New CustomersForm()
some_form.NewRec()

some_form = New SomeOtherForm()
some_form.NewRec()
=====

So now you can change the property to be of type ISubForm instead of
CustomersForm.

Have a look in the help about, when to use interfaces (interfaces, vs.
classes), they can be very helpful as a class can implement more than
one interface as well.

Chris,
Thanks very much for that. That works a treat! (and another new one for
me!) I appreciate your time in helping me out.

Just as a matter of interest, I'm now storing the topmost subform in
the Tag property of the panel so calling the NewRec function of the
interface is done with:

Dim subfrm As ISubForm
subfrm = CType(Me.pnlMainWindow.Tag, ISubForm)
subfrm.NewRec()

I'm getting there I hope! Thanks again.
Paul
 

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