Passing a form reference gives error

S

Steve Ricketts

I'm converting a VB 6 program to VB.net and in one subroutine a form is
passed by reference. Only forms that have been set up properly by the
application will be passed to this sub.

public sub setupForm(byRef theForm as System.Windows.Forms.Form)
if theForm.lstFormControls.ListCount > 0 then ' <-- error here,
lstFormControls is not a member of "System.Windows.Forms.Form"
....

The application will always pass the form with a listbox control called
lstFormControls. However, the compiler generates an error at each
reference, lstFormControls is not a member of "System.Windows.Forms.Form".
I tried CType(theForm,form).lstFormControls, thinking I'd get away with it
through late binding but got the same error. Obviously, lstFormControls is
not a standard member of Form, but how do I get the compiler not to worry
about this and let it get handled at runtime? I use this sort of technique
throughout the VB6 program so I'm looking for sort of a generic answer that
I can apply to other instances.

Thanks for any direction you can provide

Steve
 
A

Armin Zingler

Steve said:
I'm converting a VB 6 program to VB.net and in one subroutine a form is
passed by reference. Only forms that have been set up properly by the
application will be passed to this sub.

public sub setupForm(byRef theForm as System.Windows.Forms.Form)
if theForm.lstFormControls.ListCount > 0 then ' <-- error here,
lstFormControls is not a member of "System.Windows.Forms.Form"
....

Change "System.Windows.Forms.Form" to the type of Form that has a
member called lstFormControls.
The application will always pass the form with a listbox control called
lstFormControls.

If theses Form types are different types, the members happen to have the
same name but it is not the same member. Names have been introduced to make
it easier for the programmer to identify an item. They are resolved by the
compiler and shouldn't matter at runtime.

If different forms have something in common, consider inheriting from
a common base form and moving the common code into that base form. Or,
probably less suggestive in this case, implement a common interface.
However, the compiler generates an error at each
reference, lstFormControls is not a member of "System.Windows.Forms.Form".
I tried CType(theForm,form).lstFormControls,

As the reference is of type Form, "CType(..., Form)" does not make sense because
it is already Form, so it doesn't change anything.

You _could_ change the target type specified in "CType(..., TargetType)" to
a type that does have a member called lstFormControls, but that intentionally
turns off type checking at compile time. Therefore it is not the right approach.
Instead, change the type of the parameter, so that CType is not required.

thinking I'd get away with it
through late binding but got the same error. Obviously, lstFormControls is
not a standard member of Form, but how do I get the compiler not to worry
about this and let it get handled at runtime?

Instead of doing time consuming name resolution at run time, including the
risk of not finding the name, I'd have the compiler check the validity at
compile time.
I use this sort of technique
throughout the VB6 program so I'm looking for sort of a generic answer that
I can apply to other instances.

Thanks for any direction you can provide

Type safe programming is a major step to get stable applications and find
errors ASAP. If you switch Option Strict Off, invalid member access will
let you compile the application and you get only a warning instead of an
error.
 
A

Armin Zingler

I forgot...:
If you don't want to assign another Form to theForm, change it from
ByRef to ByVal.

If you switch Option Strict Off, invalid member access will
let you compile the application and you get only a warning instead of an
error.

I was wrong. You do not get a warning.
 
S

Steve Ricketts

Very helpful, a lot to think about. Look for me to come back with another
question or two soon... but probably not too soon! ;-)

Thanks again,

sr
 
S

Steve Ricketts

Ok, same issue, different example.

I have a module that manages comm ports. A number of different applications
use it. In the application forms there are two subroutines: CommActive and
GotCommInput. In VB6 I just set my application's form to a variable
(commForm) and then in the module I called commForm.CommActive or
commForm.GotCommInput. The same error is appearing on these lines just
like the previous example.

The only thing each application has in common is the comm module, otherwise
they are very different. I don't really want to change the type of the form
to my application's form because all the applications are very different...
or does it matter?

You mentioned "implement a common interface"... I'm not sure what you mean
by that, but does it fit this example?

Thanks,

sr
 
A

Armin Zingler

Steve said:
Ok, same issue, different example.

I have a module that manages comm ports. A number of different applications
use it. In the application forms there are two subroutines: CommActive and
GotCommInput. In VB6 I just set my application's form
to a variable (commForm) and then in the module I called commForm.CommActive or
commForm.GotCommInput. The same error is appearing on these lines just
like the previous example.

The only thing each application has in common is the comm module, otherwise
they are very different. I don't really want to change the type of the form
to my application's form because all the applications are very different...
or does it matter?

You shouldn't have to access a Form from the Module. It seems it's better to put
the code (the two sub routines) into a common base class that you can derive
your application Forms from. Something like

class MyBaseForm
inherits system.winows.forms.form

sub CommActive
'...
end sub

sub GotCommInput
'...
end sub
class

Put the class above into a dll that you reference from each application. Or,
postpone this step - if you have more time later - and just add the class
to each application just like you've done it with the Module in VB6.
(side note: in the "Add existing item..." dialog box, you can click on the
small down arrow next to the "Add" button and choose "add as link", so you
don't have a copy of the file in each project that you would have to maintain
individually.) After "MyBaseForm" is available in the application, derive
all Forms from it. You don't need "commForm" anymore because the methods
are now part of each Form. The Module "hack" in VB6 was required because
of it's lack of inheritance.

May I ask why the Comm code needs to access a Form? Comm port communication
is not a UI task and therefore should be decoupled from UI classes like
Forms.
You mentioned "implement a common interface"... I'm not sure what you mean
by that, but does it fit this example?

I think it does not fit. If you'll have a different case, I'll give you an
example where an Interface makes sense. :)

If you're interested in it:
http://msdn.microsoft.com/en-us/library/28e2e18x.aspx

(BTW, COM, that VB6 is based upon, is all about interfaces, but that's another story.)
 
S

Steve Ricketts

May I ask why the Comm code needs to access a Form? Comm port
communication is not a UI task and therefore should be decoupled from UI
classes like Forms.

Basically, the module accesses the form because, in this case, the comm port
is receiving raw audio packets from a RF wireless remote control. There is
a 3rd party control on the form (component) that takes the raw audio and
converts it into GSM format. The sub also displays wireless keypad values
on the form and then sends them to a central location via IP (which could be
done in the module).

The other problem I have is that even though the sub names are the same
(CommActive, GotCommInput), what they are doing with the data from
application to application is completely different. All the module knows is
it's ready to read (CommActive) and that it has data that should be
processed (GotCommInput). It's the application's implementation of those
subs that does something different with the data.

sr

PS. Notice the "de" in your address. We have an office in Quickborn.
 
A

Armin Zingler

Steve said:
Basically, the module accesses the form because, in this case, the comm port
is receiving raw audio packets from a RF wireless remote control. There is
a 3rd party control on the form (component) that takes the raw audio and
converts it into GSM format. The sub also displays wireless keypad values
on the form and then sends them to a central location via IP (which could be
done in the module).

The other problem I have is that even though the sub names are the same
(CommActive, GotCommInput), what they are doing with the data from
application to application is completely different. All the module knows is
it's ready to read (CommActive) and that it has data that should be
processed (GotCommInput). It's the application's implementation of those
subs that does something different with the data.

Sorry, my fault... I mixed it up a bit. The subs are in the Forms, not in the
Module.

Anyway, what you've desribed above looks as if a complete redesign of the
application is advisable. I can only make the general suggestion to encapsulate
all tasks in separate classes with as little relations as possible. Everything that
is not UI related shouldn't need a UI (a Form) to work.
sr

PS. Notice the "de" in your address. We have an office in Quickborn.

~400 miles away from here. (which is pretty far in de ;) )
 
J

Jack Jackson

I would use an Interface.

Define an Interface with two methods: CommActive and GotCommInput.
Define this interface in a project that is referenced by the projects
that have the forms.

In each form class at the top of the class put:
Implements <<name of the inteface>>

In each form class you will then need to add methods that specify
Implements <<name of the interface>>.CommActive, and the same for
GotCommInput.

To call those methods given a reference to a form:

Dim myinterface As <<name of the interface>> = TryCast(<<form
reference>>, <<name of the interface>>)

If myinterface is not Nothing, then the form reference implements the
interface and you can call the methods using myinterface.CommActive
and myinterface.GotCommInput.

All of this is written from memory, so the syntax may not be quite
correct.
 
S

Steve Ricketts

Syntax not nearly as important as the concept. Sounds like a good one.
I'll give it a go!

Thanks for the response!!

sr
 
J

J.B. Moreno

Steve Ricketts said:
The only thing each application has in common is the comm module, otherwise
they are very different. I don't really want to change the type of the form
to my application's form because all the applications are very different...
or does it matter?

What you want is an Interface and Implements -- that gives you the
compile time check on the function/method name, but doesn't require
that the actual code be the same or the class types to be other wise
related.
 

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