I have a VB.net program that I received from someone else. I am trying to make modifications to it. The program consists of one main form and 6 classes (all .vb files).
In the main form, I want to call a sub-routine in one of the other modules. What is strange is that if I enter the name of the module followed by a ".", i.e.
QuoteMgr.
I don't see the names of the sub-routines in the module. I only see the Public Const's that are defined.
The sub-routine that I want to call is in a section labelled:
#Region "Methods"
What do I need to do to be able to call one of these methods?
The confusion was because of the wording you used in your original question before you edited it to say "class" instead of "module".
The two terms in VB.net mean entirely different things. A class typically must be insantiated as an object to invoke its methods.
So what you need to do is:
dim qt as new QuoteMgr
qt.Method("foo");
In this case you're creating an instance of QuoteMgr called qt and then invoking its methods. Alternatively you could modify the QuoteMgr class and set the method you're trying to call to "Shared" and then call it by simply going "QuoteMgr.Method" as you were trying before.
A module is more like a free-standing library of methods that can be called by anything in the same project (by default).
Related
Compile error:
Cannot define a Public user-defined type within an object module
What does the above compile error mean in Visual Basic for Applications (VBA)?
I would like to point out that the exact same code had no error in a separate empty Powerpoint file.
Thank you.
You need to understand the different types of code modules in VBA. Basically, you can have
A regular module - here you put in code like subs, functions, types
A userform - I guess you know what a userform is. It contains the layout of the form and the so called code behind - that is all the code that is glued to the form, like event triggers.
A class module. A class is an own, user defined type. Additionally to a simple UDT (user defined type), a class has it's own functions and subroutines (yes, I know, this is extremely simplified)
Depending on the environment, you can have build-in modules. In Excel, these are Workbook and Worksheet modules, in Word the Document module (as far as I know in Powerpoint, there are no build in modules).
Now, all of the above, except for a regular module, define classes (user forms, worksheets, workbooks, documents are special kind of classes). And a class cannot contain a public type (it is already a public type), as simple as that. It's similar to the fact that you cannot define a Type within a Type.
I assume that you have your type defined in a user form code. If you need the type only within that form, declare it as private. It is allowed to define types within a class, but they need to be private, with other words, the type in unknown in other modules of your project, and, as a consequence, you cannot have public variables of that type or public functions that return that type.
If you need the type in more than one module, you need to move the type definition into a regular module (this is what GSerg wrote in the comments)
I'm trying to convert WinForms app into a class library - long story short the production environment I'm working in will allow our users to make changes to DLLs but not EXEs, so I'm trying to shove an entire existing app into a DLL and then just create and show an instance of the startup object/form from a second WinForms app with the goal of creating some kind of auto-update system.
I've changed the output type of the project to Class Library, added the launcher app, etc, but attempting to build the old app as a class library throws hundreds of errors, almost all of which are Reference to a non-shared member requires an object reference.
Upon inspection, these errors are appearing everywhere in the code that the startup object/form or any of its properties or methods are referenced. Since a great many things in a WinForms application naturally reference the main form... this is problematic.
Stuff like:
If DbConn = n.DbConn_.Prod Then
miParent = mainform.MiProdReq
throws the aforementioned error upon the attempt to access mainform.MiProdReq
Am I missing some simple/obvious step here?
You are referring to the default instance of the mainform type in that code. Default instances are provided by something automagically generated when building Windows Forms Application projects. Class Library projects have no such thing as default instances, so any code that tries to use them will appear to be trying to access instance members as though they were Shared.
You need to put an instance somewhere and change your code to refer to that instead. If you use a global variable, which is not ideal itself but the simplest option for where you're at, then you can just do a Find & Replace In Files to find the references you need to change.
Note that default instances are something that most experienced developers would suggest avoiding anyway. They don't exist in C# and I've never heard complaints about that, so it's hardly onerous. They were added to VB as a convenience for beginners and migrating VB6 developers who weren't used to proper OOP.
EDIT:
I haven't tested it but you may be able to use Application.OpenForms(0) to get a reference to the startup form anywhere in your library. You could, perhaps, add a module like this:
Module Module1
Private _mainform As Form1
Public ReadOnly Property mainform As mainform
Get
If _mainform Is Nothing Then
_mainform = DirectCast(Application.OpenForms(0), mainform)
End If
Return _mainform
End Get
End Property
End Module
and then your code may even just work as it is.
In Access VBA we can use Me.ControlName to refer to a control name. When reading other people's VBA code I have realized that some people do not use the me keyword and simply use ControlName to refer to a control name.
Is one more efficient than the other? For me Me.ControlName is more readable but I am not sure what other people's opinion is.
There are several cases when you need to use Me:
When there are conflicting names:
Dim someControl As Access.Control
Set someControl = Me.SomeControl
Obviously, this example is contrived, but there are real cases where conflicting names are logical
When you need to refer to the form object itself:
In an external module:
Public Sub DoStuffWithForm(someForm As Access.Form)
'Does stuff with form
End Sub
In the form module:
DoStuffWithForm Me
Me is just a general VBA concept. All class modules (and by extension, form modules) use the Me keyword to refer to themselves, but don't need to do that to refer to public properties. It's in a way similar to using Application.Something, you also don't need to do that, but it increases clarity when you do. And only in specific (rare) cases it's required.
In VB, Me is the internal reference to the public interface of a class.
Things that can be referenced by Me in a class:
Public properties, subs and functions
Controls in Access form and report classes
Things that cannot be referenced:
Private members of a class, including variables, properties, subs and functions
There are three uses of Me:
Provide a self-reference when calling functions or subs
Call the right method in case of duplicate names
In the IDE, typing Me. to more quickly select controls -- Thanks to Vlado for that suggestion!
Example:
If there is a Public Foo() defined in a standard module and a Public Foo() in a class, Me.Foo will always call the class method, and plain Foo will do the same.
However, if you delete or rename the class's Foo() method, Me.Foo will throw an error, but all plain Foo references will now call the global Foo() function instead!
As a programmer, I certainly don't want code that magically starts calling a different routine without warning if I edit a class module!
This is the best argument for always using Me to reference public members within class code.
I use Me.ControlName just to make sure when I type that the control is on the form and I do not misspell it. It will appear in intellisense so I could confirm it by pressing TAB.
I am moving some code from my main project into a dll in order to make my application more dynamic (the dll can be exchanged for another one, sort of a plugin). Several subroutines in my main project have been bundled into one in the dll, and different pieces of code are run depending on a variable passed from the main project. This is in turn selected from a database which is updated by the dll as it is loaded, making it possible to add completely new functionality without having to install a new version of the app.
Now, except for arguments being passed from the calling code to the subroutine in the dll, the code in that sub also uses values of some publicly declared variables that keep track of things like the source path of input data, whether the user has made changes to some objects etc. Before moving the code, these were declared in a module of my main project. The values are now, however, needed by the sub in my dll.
I could pass all those variable values as arguments to the sub in the dll even though most of them are not used every time the call is made (since I only use one sub for everything that the dll does). This seems like the simplest solution. However, I know that having methods with like 10+ parameters is considered bad practice. Or I could move the public variables to an interface dll (which already exists), values of which both my main project and my dll can access and update the values there.
Which is best (or least bad) in terms of performance? Could one of the choices have unexpected consequences?
This gives me the impression that your methods might be shared. You should instead pass these configuration parameter to the constructor of the object and keep those value as class variable. Then, your method can easily get the values from the class.
Class SomeClass
Public Sub New(ByVal someParameter As String)
Me.SomeParameter = someParameter
End Sub
Public ReadOnly Property SomeParameter As String
Public Sub SomeMethod()
' Can use Me.SomeParameter here
End Sub
End Class
I am new to vb.net and very frustrated.
Like all good programmers I want to split my code into separate files based on functionality . Some of my code interacts with users via Forms and some interacts with lab equipment behind the scenes (no direct user interaction). Sometimes a user will change something that will impact the lab equipment and sometimes something will happen with the lab equipment that a user needs to be aware of. When I use VS to create files I have to choose a Module or Form. VS then creates an empty file with a with either
Public Class Foo
End Class
or
Module Foo
End Module
If I have a bunch of files, each a Module, and if I define routines in a Module to be Friend then I can call them from other Modules, so:
Module Foo
Friend Sub DoSomeWork()
End Sub
End Module
Code in Fee can call routines in Foo -
Module Fee
Friend Sub Stuff()
DoSomeWork()
End SUb
End Module
When I create a Form, VS creates a Class. I find that I can call subroutines defined in a Module from a Class but when I try to call from a Module into a Class I get an error that the routine I am trying to call is not declared. I also cannot call from one Class into another Class. Declarations seem to apply only to library routines outside my program.
I have looked through several online explanations and tutorials, but frankly I don't understand these nor do I care about "inheriting from the base class" and all the other gobbledygook that such "explanations" contain. I want to concentrate on building my application.
My Main form has the name "Main"
I tried putting all the module code into the Main Class first by renaming "Module Foo" to "Public Partial Class Main" - bad idea - creates an impossible-to-find duplicate error. I tried creating empty code files, defining them as Public Partial Class Main and putting the Module code into them, - this worked in that code in the Class Main could call the "Module" code (which was now in Main) and vice-versa, but, other Forms (of course I have more than one) are created by VS to have their own Classes and once the "Module" code is moved out of Modules into Class Main the other Forms(Classes) could not call the code anymore.
I just want some recipe (best practice) I can follow to for defining Modules and Classes so that code and data can be shared.
ANSWER from below
To invoke a subroutine in another Class you simply need to put the class name in front of the subroutine name.
So not
DoSomeWork()
but
Foo.DoSOmeWork()
This may be obvious to all of you experienced programmers but not to me. You do not have to prepend a class/module name to a Module-to-Module call or a Class-to-Module call, only to calls that are made into Classes. Personally, for the sake of consistency, I think the things should be the same, but it would probably violate some OO rule. Anyway thank you to all.
Generally, if you have a function that needs to be called from more than one form, or from forms and modules, put it in the main module. If you have an exceptional case and need to call a function or sub in a form from another form or a module, you can declare it to be public:
Public Class Form1
public sub test(i as integer)
...
end sub
end class
and then you can call it by referring to the class.subname:
call form1.test(7)
NomD,
Like all good programmers
you should indeed care
about "inheriting from the base class" and all the other gobbledygook that such "explanations"
This will make you a better programmer and taking the time to understand why proper code structuring is important will also begin to yield better results for you.
I am not sure why two commentors seem to have an issue with VB.Net. The question would be the same regardless of the language, since both are C# and VB are built on .Net. Code can be written poorly in C#, just like VB. Please leave the language wars at home. NormD, the answer to your question should really be to direct you to the resources needed to better understand the problem. Here is an article on scope that might help a bit - class scope. The reason you are getting the behavior that you see is due to what you are working with. Modules (similar to static classes in C#) are created when you program begins, so there is no need to create them. So you can reference a method on a module, like so - module.method. Classes on the other hand, some exceptions, need to be created in order to be referenced. So to use an employee (or form class) you must create a variable of that class. So you would use dim myemp as New Employee() and then call myemp.method() from your module. This is a rather simplistic description, so please read the scope article and other MSDN articles for more information. I am sure other posters can post additional links with good information. Hope this helps a bit.
Wade
It seems like you don't understand the basics of object-oriented programming (OOP).
If you DON'T want to learn how to design your application in an object-oriented way, then only create modules in your application and you will be able to call functions from one to another without any problem. But this will result in code that will not be easily maintainable and scalable.
The other option is to learn OOP by picking a book about it, or following a course or tutorial on the subject. It's a significant investment but it will result in more robust code that will scale better when your application grows.