Intellisense in private modules - vba

Assume I have a module named Module1 with the following code:
Private Sub MyPrivateSub()
'do something
End Sub
Public Sub MyPublicSub()
'do something
End Sub
Public Sub test()
End Sub
If I place the cursor inside Test() and start typing "MyPrivateSub" or "MyPublicSub", I don't get any intellisense. I can type "Module1." (or "Me." if Module1 were a class module) to get an intellisense menu, but this only contains the public method MyPublicSub, as shown here:
Is there some way to get an intellisense menu for all members, public and private? I'm working on a project with modules that have many methods, and going up and down continually to copy/paste member names is time consuming.

Short answer
hit a combination of
CTRL+SPACE
and start typing the sub name like shown here
Long answer
Everything you do in programming matters. When you decide to make your sub/function/variable private you do that for a reason and you need to understand how this will affect the access level and "scope".
The scope of a member is dictated by its access level and in VBE anything that is private and qualified with it's parent member does not get intelli-sense. Simply, because you can't (are not supposed to be able to access it) from the outside.
Because your MyPrivateSub access level is Private you can't access it with intelli-sense through qualifying the module with Module1..

If you're starting from fresh, you can do the following:
for all your private sub function, name them into a standard format but as public function at the moment, for e.g.:
Public sub iamprivate_calDate ()
Public sub iamprivate_getsetfunction()
...
after you're completed with your macros, simply find and replace all your "Public sub iamprivate" into "Private sub " in your editor.

Related

Accessing Form controls from a module

I am trying to create a sub in a module that simply hides a lot of panels for a Form which is passed as a parameter to it. Basically, Ill have a button called students and a button called subjects and I want that when I click on the, lets says, students button ALL the panels I define in the function get hidden, and only the students panel remains visible.
When I run this code I get :
System.MissingMemberException: 'Public member 'pnlAlumnos' on type 'Ventana_Principal' not found.'
Code in my module
Module Modulo_Comportamiento_Ventanas
Public Sub Esconder_todos_los_paneles(ventana As Object)
ventana.pnlAlumnos.Hide()
ventana.pnlMaterias.Hide()
End Sub
End Module
Code on the main Form click
Private Sub btnAlumnos_Click(sender As Object, e As EventArgs) Handles btnAlumnos.Click
Esconder_todos_los_paneles(Me)
Me.pnlAlumnos.Show()
End Sub
How can I modify my code in order to being able access the panels and hiding them?
Thanks in advance!
Note : BTW, I know I can do this, but I want to know why it does not work the way I am doing it, I mean the below code looks horrible ( not that my other path looks any more nicer) :
Public Sub Esconder_todos_los_paneles()
WindowsApp1.Ventana_Principal.pnlAlumnos.Hide()
WindowsApp1.Ventana_Principal.pnlMaterias.Hide()
End Sub

Prevent implicit import of modules [duplicate]

I have a situation where I have several VB.NET Modules in the same Logical-Module of a large application.
I would like the update function of each module to be public, but I would like users to be forced to qualify the function call with the module name.
ModuleName.Update()
instead of
Update()
Is this possible?
Thanks.
No.
The VB.NET specifications automatically use Type Promotion to allow this behavior to occur. The only way to avoid this is to have a type at the namespace that has the same name (Update) which would prevent (defeat) the type promotion provided in VB.NET.
Yes, it is possible, if you are willing to wrap the module within a namespace of the same name as the module:
Namespace ModuleName
Module ModuleName
...
End Module
End Namespace
Using modules is usually a poor design, because its methods become visible directly in the name space.
Consider replacing them with Classes. Put Shared on all the members:
Class ClassName
Public Shared Property SomeData As Integer
Public Shared Sub Update()
End Sub
End Class
Update would be referenced as:
ClassName.Update()
Make it impossible to instantiate, by having a Private instance constructor (is NOT Shared):
Private Sub New()
End Sub
Any needed class instantiation can be done like this:
Shared Sub New()
... code that runs once - the first time any member of class is accessed ...
End Sub

How to make a function/sub available to all forms in a project?

I have a sub that I want to be available to (or "callable from") all forms:
' Call some Sub from another form.
someSub()
I'm having difficulty finding examples online thus my suspicion that the crux of my issue may be terminological.
How?
Can anyone guide me as to what I should be looking at?:
Global Sub
Static Sub
Shared Sub
Private Sub
Where?
Where should I position my "universal" sub?:
Arbitrarily place it in one of the forms.
Create a code file and somehow integrate into it each form?
declare it as public Sub inside a Module
Public Module GlobalFunctions
Public Sub YourSub()
End Sub
End Module
hope this will help you
Make it public.
Public Sub MySub()
Then you can call it from every form.
Myform.MySub()

Executing function on hundreds of databases

I want to embed a simple piece of VBA Code in Access 2007. I need to execute this code on hundreds of different Access DBs, so I don't want to manually paste the code into each and every DB. Is it possible to do this? Maybe by way of an add-in?
Thanks
Karl
EDIT
I want to execute the following VBA code:
DoCmd.DeleteObject acTable, "LastNum"
DoCmd.TransferDatabase acLink, "ODBC Database", "ODBC;DSN=myDB;UID=User1;PWD=123;LANGUAGE=u s_english;" & "DATABASE=LastNumber", acTable, "LastNum", "LastNum"
How would I translate this into a VB addin?
The visual studio VB add-in template looks like this:
imports Extensibility
imports System.Runtime.InteropServices
<GuidAttribute("B61E2444-F46E-4591-A8BA-3D06A4E5D84C"), ProgIdAttribute("MyAddin1.Connect")> _
Public Class Connect
Implements Extensibility.IDTExtensibility2
Private applicationObject As Object
Private addInInstance As Object
Public Sub OnBeginShutdown(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnBeginShutdown
End Sub
Public Sub OnAddInsUpdate(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnAddInsUpdate
End Sub
Public Sub OnStartupComplete(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnStartupComplete
End Sub
Public Sub OnDisconnection(ByVal RemoveMode As Extensibility.ext_DisconnectMode, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnDisconnection
End Sub
Public Sub OnConnection(ByVal application As Object, ByVal connectMode As Extensibility.ext_ConnectMode, ByVal addInInst As Object, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnConnection
applicationObject = application
addInInstance = addInInst
End Sub
End Class
EDIT PART 2:
Ok, so I figured out I should do the following:
imports Extensibility
Imports System.Runtime.InteropServices
Imports Microsoft.Office.Core
Imports Access = Microsoft.Office.Interop.Access
<GuidAttribute("B61E2444-F46E-4591-A8BA-3D06A4E5D84C"), ProgIdAttribute("MyAddin1.Connect")> _
Public Class Connect
Implements Extensibility.IDTExtensibility2
Private applicationObject As Access.Application
Private addInInstance As Microsoft.Office.Core.COMAddIn
Public Sub OnBeginShutdown(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnBeginShutdown
End Sub
Public Sub OnAddInsUpdate(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnAddInsUpdate
End Sub
Public Sub OnStartupComplete(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnStartupComplete
End Sub
Public Sub OnDisconnection(ByVal RemoveMode As Extensibility.ext_DisconnectMode, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnDisconnection
End Sub
Public Sub OnConnection(ByVal application As Object, ByVal connectMode As Extensibility.ext_ConnectMode, ByVal addInInst As Object, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnConnection
applicationObject = CType(application, Access.Application)
addInInstance = CType(addInInst, Microsoft.Office.Core.COMAddIn)
' This line enables VBA to call back into this object.
addInInstance.Object = Me
End Sub
Public Sub ChangeLink()
applicationObject.DoCmd.DeleteObject(Access.AcObjectType.acTable, "LastPolNum")
applicationObject.DoCmd.TransferDatabase(Access.AcDataTransferType.acLink, "ODBC Database", "ODBC;DSN=ZACANTDB02;UID=EDIPolicyNumber;PWD=museum123;LANGUAGE=u s_english;" & "DATABASE=EDIPolicyNumber", Access.AcObjectType.acTable, "LastPolnum", "LastPolNum")
End Sub
End Class
Now what I want is to be able to execute ChangeLink() from Access. How do I do that?
Depending on what the code is for, there are (at least) two different ways to do this, without working at the VB Extensions level (which is where you'd copy and paste code, at least in VBA):
Make the code part of an add-in. It can then be loaded, and stay loaded and exposed, to any other application.
If the code is working on data only, consider writing a procedure that links and unlinks the table(s) in each mdb file that needs processing.
The advantage of #2 over #1 (and, indeed, over copying and pasting code) is that you can invoke your simple routine once, not hundreds of times.
EDIT:
There are two ways to invoke an add-in, depending on who is meant to invoke its functionality, and how.
Through the UI. Use this when you want an end user to be able to use it, especially practical for functionality you'll invoke often. How to:
a. Office button > Access options > Add-ins tab
b. If it's a .NET add-in (or any other non-Access add-in), choose COM Add-in from Manage dropdown. If it's Access, choose Access. Click go
c. Click Add button in the form that pops up, browse to the add-in.
You will still need to provide some sort of UI to it: a commandbar, a ribbon button, a form, something. That's a separate discussion
Through code. Use this if you're just wanting to invoke it as part of some other VBA procedure.
a. VBE window > Tools > References
b. Browse button
c. Change the dropdown in file of type if you're setting up an Access add-in.
You can then call the line of code directly, as if it were part of your current project. If you wish to be more explicit, you can also invoke it by library name: MyAddInName.ChangeLink
Seems to me that you don't need to run this code from the Access databases -- all you need to do is run it on all the databases.
To do that, you'd use DAO to open each database in turn, delete the table, then create the link. You'll have to do both of those steps with DAO (deleting from the TableDefs collection, and adding to it) rather than with DoCmd operations (which are unavailable through DAO).
Of course, if the databases are no accessible from a central location, you can't do this. But if that's the case, how would you alter the code or invoke an add-in?
Another way to use a library database is to use Application.Run:
Application.Run "\Server\PathToAddIn\MyLibrary.FixTables"
This assumes:
MyLibrary is an MDE/ACCDE.
in MyLibrary database is a subroutine or function called FixTables that runs the code you want to execute.
Indeed, with that method, you can actually use DoCmd, since the add-in is running within Access and in the context of the currently opened database.
However, note that some people seem to have difficulties executing add-ins in this fashion (I'm currently in a long discussion with somebody in another forum who can't seem to get it to work). I've been using this method for library databases for years and years and have had no problems (as long as you specify a full path), so I'm puzzled why the ones I'm discussing it with can't seem to make it work.

Shared method in VB.NET cannot handle this why?

(I tried with this question but this code isolates the problem better.)
I have this code:
Public Shared Sub PopulateTextFields(ByRef stuffList As List(Of Stuff))
Dim aStuff As New Stuff
For Each aStuff In stuffList
DoStuff(aStuff)
Next
End Sub
Private Sub DoStuff(ByRef theStuff as Stuff)
....
End Sub
I get the following error highlighting DoStuff(aStuff):
Cannot refer to an instance member of
a class from within a shared method or
shared member initializer without an
explicit instance of the class.
Didn't I get an explicit instance of Stuff when I wrote the Dim statement?
Don't understand what's wrong. Thanks in advance!
I think the problem lies with the Subroutine DoStuff. If both your subs lie in the same class, you are trying to refer to DoStuff from within PopulateTextFields, which is a shared sub.
In order to achieve this, you need to declare DoStuff as Shared as well.
Yes you did, but you aren't referencing aStuff you are trying to call it on the static implementation of the class, furthermore you are resetting aStuff to a separate instance through each loop iteration.. change your code to:
Public Shared Sub PopulateTextFields(ByRef stuffList As List(Of Stuff))
Dim aStuff As New Stuff
For Each aStuff In stuffList
aStuff.DoStuff(aStuff)
Next
End Sub
Private Sub DoStuff(ByRef theStuff as Stuff)
....
End Sub
And it should work, but maybe not as expected, I don't really know your intent of having a private member that handles changing a separate reference of it's own type.
It may be appropriate to change the signature of DoStuff to:
Private Sub DoStuff()
....
'Use the Me reference here to change myself
....
End Sub
and then call it as:
aStuff.DoStuff() 'Will modify this instance
You didn't share which type these methods belong to. From your confusion, I'm guessing it's part of the "Stuff" class. But it doesn't really matter. It sounds like you're forgetting one of two things:
Creating an instance of the type in the shared method doesn't somehow attach the shared method to that instance. You could create 10 or 1000 instances in the method, after all.
Passing an instance as a parameter doesn't associate the function with an instance. A parameter is not a call site.
Either way, it comes down to providing an instanced call site. Your DoStuff function is not shared, and so the compiler thinks it needs access to state provided by a specific instance of your type. That instance is the method's call site. You either need an instance of the type to call it from: SomeInstance.DoStuff(aStuff) , or if the method doesn't really need access to any type state you need to mark it shared and call it like this: Stuff.DoStuff(aStuff)