Where to place function declarations? VB.NET - vb.net

I'm wondering where to place my function declarations in my project. For this project I am supposed to modularize the coding which currently lies under Button Calculate (previous project) but everytime I try to place it under button calculate it tells me it doesn't belong within the method body. So how would I go about doing this?

Hmm. I dont want to sound condescending at all in writing this, but I'm guessing that you're trying to put a function directly under a line of code that says something like..
private Sub ButtonCalculate()
This is the start of a subroutine definition. Try looking further down the code for the line that says..
End Sub
and put your function declaration under there - leaving a blank line for readability's sake e.g.
private sub ButtonCalculate()
'code for buttoncalculate
'more code for buttoncalculate
'lots more code for buttoncalculate
End Sub
private Function randomFunction(WhateverYourParametersare byval integer) as integer
'your function code
'more function code
End Function

Related

VBA Calling a private function inside of a userform

I have a userform defined as "SingleListForm".
I have a private sub named "loadSingleListForm(ID As Double)"
I am attempting to pass a variable into the form and I was implementing it in the fashion that loadSingleListForm would set the form up based on ID, basically re-using one form to show variable data from variable sources in the listbox.
But calling a standard Intersect from outside the form (Worksheet_SelectionChange) these two options compile but do not work.
Application.Run "SingleListForm.loadSingleListForm", ID 'ID already declared and assigned
This doesn't work either
Call ActiveWorkbook.UserForm("SingleListForm").loadSingleListForm(ID)
Where it says UserForm I have also tried SingleListForm.
Here the runtime error is:
I am trying hard not to use a Global Variable here to pass to the form.
Perhaps I should go to Initialize and try something there.
I am trying to pass the variable to the form and then of course set up the form based on this case and then show the form. you can't pass with show so you have to find another way to set up.
I just realized I have not called a userform private function from outside of the form before, but I do it with modules all the time. The first case works in that instance.
Cheers,
-WWC
The better way to do this is to declare a property to the form. In the form's module enter
Option Explicit
Private myID as double
Property Set ID(i as double)
myID = i
End Property
Then your function
Private Sub loadSingleListForm()
can refer to myID with in it's code
To Use this from outside modules you use
Load SingleListForm
SingleListForm.ID = ID 'ID variable already declared
Declare your sub in the form as Public Public Sub loadSingleListForm(ID As Double) and then call it like this SingleListForm.loadSingleListForm ID
Just to cover this. Empty workbook, one button.
The button calls to a private function in the form that does nothing but open a message box. Testing concept here.
This is all there is:
Doesn't work:
UserForm1.you_made_it
Error at compile, method or data member not found
Same if this:
With ThisWorkbook
UserForm1.you_made_it
End With
Then try this:
Application.Run "UserForm1.you_made_it"
Error: Cannot run macro . . . .
Try this from first comment:
ActiveWorkbook.UserForm("UserForm1").you_made_it
Error: Object doesn't support this property or method
So this is the winner from above. Not sure I wanted to go Public but it works.
Doesn't solve how to use a private member in the form but it gets the coding going forward.
Public Sub you_made_it()
MsgBox ("you made it")
End Sub
So far:
1) Move the private to a module and then call it
2) make the function Public and it works
Thank you,
-WWC

VBA - Custom Function to close work book - not working

I am trying to write a simple function (in a module FileIO) which would take an instance of a work book, and just close it. This function is invoked from another module Business.
Below is the code snippet.
Public Function CloseExcelFile(wkBook As Workbook)
If (wkBook Is Not Nothing) Then
wkBook.Save
wkBook.Close
End If
End Function
I invoke this method by using the command FileIO.CloseExcelFile(catWorkBook). Variable catWorkBook is the object reference to the workbook I created (in a step before).
When ever I try too invoke the custom function, I am getting the error
object does not support this method or property
The below command closes the work book with no errors.
catWorkBook.Close
But the same does not happen when I use the custom function. What is going wrong here?
You just have your Not in the wrong place. Try it like this:
Public Function CloseExcelFile(wkBook As Workbook)
If Not wkBook Is Nothing Then
wkBook.Save
wkBook.Close
End If
End Function
As braX pointed out, your Not isn't in the right place.
You also don't need a Function here. Change it to a Sub. In fact, you barely need the Sub when you reduce it to one line like this:
Public Sub CloseExcelFile(wkBook As Workbook)
If Not wkBook Is Nothing Then wkBook.Close(SaveChanges:=True)
End Sub
The error was due to the INCORRECT way I was invoking a sub routine. I invoked the sub routine as:-
FileIO.CloseExcelFile(catWorkBook)
The CORRECT way to invoke a function would have been.
FileIO.CloseExcelFile catWorkBook

VBA Excel Call and Run breaking backtracking

I'm making a workbook with a whole lot of different subs, and in an effort to avoid a user accidentally activating a sub that erases the code of a sheet for example, I've tried making all the subs private instead.
My subs can now only be activated by clicking buttons on the worksheet, and it all works as intended. Untill a sub of mine tries to call a private sub in another module of course.
To get around this I used Application.Run rather than Call, which worked and also allows me to call in a variable "NextSub" from the previous sub, which gives me some flexibility that I need, and apparently cant get with the Call.
Eg.
Sub FirstSub()
*Something going on
Application.Run "SecondSub", SomeVariableSub
End sub
Sub SecondSub(Nextsub as String)
If something Then
*Do something
Application.Run NextSub
Else
Application.Run NextSub
I thought that the Application.Run had solved all my problems, but I used to have a line that called an errorhandler, which in turn called a sub. It seems that the program can no longer backtrack to the sub that contained the errorhandler as it could when I used Call.
Does Applciation.Run break this functionality? If yes, can I then use Call with a variable NextSub as I am doing it now? And if I can't use the Call that way, then is all this fixed by adding a On Error GoTo ErrorHandler in the affected subs?
I know that the whole thing about calling Private Subs across modules is probably pretty bad practice, but I was compltely new to this when I started out, and the project is too extensive to fix that without rewriting all of the code.
Instead of making all subs private, either put Option Private Module on top of each module, or add a dummy argument to each routine:
Sub SomeHiddenRoutine(bDummy As Boolean = False)
'Routine can be called as usual using:
SomeHiddenRoutine
End Sub
If I understand you are trying to call a function specified by a string.
The correct way is to use something like this, which allows you to call all the private subs (as long as it is in the same module as the private functions):
Sub CallFunction(FuncName As String)
Select Case FuncName
Case "Func1": Func1
Case "Func2": Func2
Case "Func3": Func3
End Select
End Sub

Visual Basic Console - A global command & anwser string

I'm creating a text based adventure game and would like to create some "global" commands & answers that would work anywhere no matter where your are.
For the global answers if we look at this code:
Module Module1
Private Property answer1 As String
Private Property answer2 As String
Sub Main()
Console.WriteLine("Welocome to the training grounds!")
Console.WriteLine("What would you like to do? 1. I would like to train on dummies")
answer1 = Console.ReadLine()
Console.WriteLine()
If answer1 = "1" Then
Console.WriteLine("Okay what now?")
answer2 = Console.ReadLine
If anwser2 = "1" Then Console.WriteLine("New option")
End If
End Sub
Now as you can see I have to create a string for each new user input. I've tried doing a Public answer As String = Console.ReadLineand then having things react to "answer" but if I reused a keyword like number 1 in the code up top the program would not wait for user input and just go down the path of number 1. The first option seems like a bunch of spagettih code and the second option dose not seem to work or I myself am not getting it to work so any tips here would be nice.
I also want to know if its possible to create a global string or something of sorts. Say that No matter if I were at the point where I'm supposed to give input to answer 1 or 2, if I typed in "inventory" it would open another sub called inventory. Now if possible I want to do this without having to have an if answer = inventory then Inventory().
Thanks in advance everyone ^^
Following the advice given to my by b.pell I was able to create a "GameCommand" sub but I'm not facing a problem of how to implement these into the game itself/make them accessible without ruining the game flow. I am also not quite sure how to write a command that will modify something in GameCommand.vb (say if the player gets an item how would I add it to the inventory list?)
Module Module1
Sub Main()
Dim gc As New GameCommand
If Console.ReadLine = "Go to dummy" Then Dummy() Else
CallByName(gc, Console.ReadLine, CallType.Method, "")
End Sub
Sub Dummy()
Console.WriteLine("I am dummy hear me roar")
Return
End Sub
End Module
The GameCommand.vb file is the same as the one in p.bells comment.
You could create an interpreter function that processes all commands and then do what you want in there. So everytime you read input in, just pass it along to the interpreter sub.
interpreter("inventory")
Inside of there, you could do an break that command up (if it has arguments). You could do a basic if statement and execute your sub procedures based off of that.
You could go above and beyond (this answers your question about not having to write the if's) and create a commands class that has all of your command methods on it (Inventory, North, South, East, West, Look) and then when a user enters a command you could use reflection to check that class to see if that sub/function exists (and then invoke it). The benefit of that is, as you add methods to the command class you never have to update the if logic in your interpreter again.
E.g. You would add a "Public Sub Look()" or "Public Sub Look(args as String) to the command class.. your interpreter would then try to invoke the look command (and maybe pass it the rest of the arguments). If it wasn't found, you tell the user it wasn't a command, if it was, it executes (google search for invoking). This means as you add Sub's the interpreter just picks them up.
Here is an MSDN article that should get you going, you can use VB's CallByName function, you pass it your class, then the proc name you want to execute with an args:
https://msdn.microsoft.com/en-us/library/chsc1tx6(v=vs.80).aspx
Here is a simple example (a console application):
Module1:
Module Module1
Sub Main()
Dim gc As New GameCommand
CallByName(gc, "Inventory", CallType.Method, "")
' Will look south
CallByName(gc, "Look", CallType.Method, "south")
' Will try to look southeast, but we don't accept that as a valid direction
CallByName(gc, "Look", CallType.Method, "southeast")
Console.ReadKey()
End Sub
End Module
GameCommand.vb:
Public Class GameCommand
Sub New()
End Sub
Public Shared Sub Inventory(arg As String)
Console.WriteLine("Execute code to show inventory")
End Sub
Public Shared Sub Look(direction As String)
If direction <> "north" And _
direction <> "south" And _
direction <> "east" And _
direction <> "west" Then
Console.WriteLine("Invalid direction")
Exit Sub
End If
Console.WriteLine("You look " & direction)
End Sub
End Class
I would approach a text adventure with the following general structure:
In your main module, loop through the process of each "turn".
Display any prompt text, as appropriate.
Read user input.
Check list of global commands and execute as appropriate.
Check list of local commands and execute as appropriate.
Display an error message.
Each command you execute should do the following:
Calculate changes to any variables affected by the command
Check each possible change in game status from the top down, and execute subsequent commands as appropriate. (E.G. Player death, mission success/failure, enemy defeated, etc.)
Advance the story to the appropriate place.

how to call a sub with input between the parenthesis vb.net

I want to call a sub from within another sub. The problem is there is a variable in the event handler that appears nowhere else in the code. I think it is an array of data fed by an API. the variable in the event handler parenthesis is called 'positions'. the syntax inside the event handler parenthesis is:
ByVal positions as X.API.UpdateList
I haven't code vb.net but if you are using ByVal you are actually referencing the value
of the variable positions to another variable in you main sub that holds the same data.
So try calling the Private Sub like this:
Call update(positions)
Take note that positions must be declared with the same data type in your main sub like this.
Dim positions as X.API.UpdateList
And of course it holds your required value for use in your private sub.
Hope this helps.