How to exit a main sub within a called sub - vb.net

I have 2 subs that look like this:
How can i stop my "main" sub if my statement is true in the sub i just called?
Public Sub main()
call run()
more code....
End Sub
Public Sub run()
If ProgressBar1.Value = 100 Then
(i want to stop the code running if this statement is true, it shall not continue in my main sub.)
End If
End Sub

You can't do it if Run() is a Sub. You need your Run() as a Function. return a Boolean indicating if you want to stop main, and call in inside an If:
Public Function run() As Boolean
If ProgressBar1.Value = 100 Then
Return True
End If
' some more code if needed
Return False
End Function
Then call it in your main sub like this:
Public Sub main()
' some main code here
If Run() Then
Return
End If
' The rest of main code here
End Sub

Related

How to end one procedure (Sub, Function etc) from another in VBA?

I want to end a main sub from another sub or function.
Here is an example code to illustrate what I need to do:
Sub main()
Call endMainSub
'do other stuff
End Sub
Sub endMainSub()
'here I need a code to break main Sub
End Sub
From endMainSub, I would like to terminate main sub before "do other stuff".
You should use a function for that.
Sub main()
If Not endMainSub Then
'do other stuff
End If
End Sub
Private Function endMainSub() As Boolean
Dim Fun As Boolean ' function return value
' break if A3 = "No" OR C3 > 10
Fun = (Cells(3, "A").Value = "No")
If Not Fun Then
Fun = (Cells(3, "C").Value > 10)
End If
endMainSub = Fun
End Function
Make the function Private if you aren't going to call it from another module. Remove the Private to make it Public by default.
End Finishes all code execution. Alternatively, if you need more control, have a global flag (a boolean variable), based on which execution will continue or not.

How do I exit sub where function is used?

Was wondering if it was possible to exit sub using a function :
For example
Public Function test()
Exit Sub 'does not work
End Function
Sub MySub()
test() 'Here we should Exit MySub()
End Sub
But this Trigger an error. Is there a way to do this ?
NOTE I don't want to exit the function but I would like to exit the Sub or Stop the code execution directly into my function.
That is not possible. However, if your intent is to have test decide whether or not to abort MySub, then just return a boolean from test and act on it in MySub:
Sub MySub()
If test() Then
Exit Sub
End If
End Sub
From MSDN:
Exit Function Immediately exits the Function procedure in which it
appears.
You should use Exit Function and not Exit Sub inside test()
Update:
If you wish to exit the calling sub MySub, you should return some value from the test function. For Example:
Public Function test()
test = False
End Function
Sub MySub()
If test() = False Then
Exit Sub
End If
End Sub
Try this approach, please. Your function must return something in order to exit the sub. Your sub is not automatically exited if the function is. You must set a condition inside the sub to exit it in case of a specific function return:
Public Function test(a As Long, b As Long) As Boolean
If a + b > 10 Then
test = True
Else
Exit Function ' even if it is not necessary
End If
End Function
Sub MySub()
If Not test(5, 7) Then Exit Sub
'do whatever...
End Sub

UseWaitCursor doesn't work in an async Task

My current project requires a lot of forms. A lot of logic is the same so I want to create a BaseForm from which all Forms inherit.
I encounter a problem with UseWaitCursor and Cursor.Curent = Cursors.WaitCursor, it doesn't work if I load the data async (in a new Task).
This is the BaseForm:
Public MustInherit Class BaseForm
Inherits System.Windows.Forms.Form ' Normaly in BaseForm.Designer.vb put I put it here for symplicity
Protected Sub BeginLoadingData()
Application.UseWaitCursor = True
Cursor.Current = Cursors.WaitCursor
Application.DoEvents()
End Sub
Protected Sub EndLoadingData()
Application.UseWaitCursor = False
Cursor.Current = Cursors.Default
End Sub
End Class
And I use it like this:
Public Class MainForm
Inherits BaseForm ' Normaly in Mainform.Designer.vb put I put it here for symplicity
Public Sub New()
InitializeComponent()
LoadData()
End Sub
Private Sub LoadData()
BeginLoadingData() ' Working as long as I doesn't move the mouse
Task.Factory.StartNew(Sub()
' ... Long running task
Me.Invoke(Sub() EndLoadingData())
End Sub)
End Sub
End Class
If I run the loading synchronous, all works.
I wonder how I can force the cursor to stay WaitCursor.

Raise Event Vb.net from worker Thread

I'm looking at a console app for vb.net. I'm trying to get a worker thread to raise an event to the main thread to display data on the screen (the word "HIT" everytime the worker thread completes a cycle). My code is below.
I'm not sure why but the main thread's Private Sub CounterClass_GivingUpdate() Handles _counter.AboutToDistributeNewupdate isn't executing.
Imports System.Threading
Module Module1
Private WithEvents _counter As CounterClass
Private trd As Thread
Sub Main()
While True
Dim s As String = Console.ReadLine()
Dim started As Boolean
Select Case s
Case "status"
WriteStatusToConsole("You typed status")
Case "startcounter"
If started = False Then
starttheThread()
started = True
WriteStatusToConsole("You Have Started The Timer")
Else
WriteStatusToConsole("YOU HAVE ALREADY STARTED THE TIMER!!!")
End If
End Select
End While
End Sub
Private Sub CounterClass_GivingUpdate() Handles _counter.AboutToDistributeNewupdate
WriteStatusToConsole("Hit")
End Sub
Private Sub starttheThread()
Dim c As New CounterClass
trd = New Thread(AddressOf c.startProcess)
trd.Start()
End Sub
Sub WriteStatusToConsole(ByVal stringToDisplay As String)
Console.WriteLine(stringToDisplay)
End Sub
End Module
Public Class CounterClass
Public Event AboutToDistributeNewupdate()
Public Sub sendStatusUpdateEvent(ByVal updatestatus As String)
RaiseEvent AboutToDistributeNewupdate()
End Sub
Public Sub startProcess()
Dim i As Int64
Do
Thread.Sleep(1000)
i = i + 1
sendStatusUpdateEvent(i.ToString)
Loop
End Sub
End Class
Your CounterClass_GivingUpdate() only handles the _counter variable's event (the variable that you do not use!). Every time you declare a new CounterClass it has its own instance of the event that it raises.
You know have two options:
Option 1
Subscribe to the event for each new CounterClass instance you create. Meaning you must use the AddHandler statement every time you create a new instance of your class:
Private Sub starttheThread()
Dim c As New CounterClass
AddHandler c.AboutToDistributeNewupdate, AddressOf CounterClass_GivingUpdate
trd = New Thread(AddressOf c.startProcess)
trd.Start()
End Sub
Option 2
Mark the event as Shared to make it available without needing to create an instance of the class. For this you must also change how you subscribe to the event, by subscribing to it in your method Main():
Sub Main()
AddHandler CounterClass.AboutToDistributeNewupdate, AddressOf CounterClass_GivingUpdate
...the rest of your code...
End Sub
Private Sub CounterClass_GivingUpdate() 'No "Handles"-statement here.
WriteStatusToConsole("Hit")
End Sub
Public Class CounterClass
Public Shared Event AboutToDistributeNewupdate() 'Added the "Shared" keyword.
...the rest of your code...
End Class

Use of delegates and invoke to call different sub depending on some variable

I would like to organize a class as follows (pseudocode)
Class MyClass
sub New(MethodEnabled as integer)
if MethodEnabled = 0
make MyMethod() to be Sub0()
else
make MyMethod() to be Sub1()
end if
end sub
sub MyMethod()
invoke(either sub0 or sub1 depending on "MethodEnabled" value)
end sub
sub Sub0()
some code here
end sub
sub Sub1()
some code here
end sub
End Class
What I wish is to have the sub "MyMethod()" to invoke (or "to be") either Sub0() or Sub1(), depending on how the class was constructed (either with MethodEnabled=0, or MethodEnabled=1).
I gather intuitively that I can do that by using delegates and invoke, but I am not much clear on how to actually do it, in practice.
Can anybody show me how I can possibly do this in the most elegant way. C# of VB.NET examples would be equally great. Thank you!
You need to either declare a delegate type or use System.Action, and then use an instance of that delegate type:
Class [MyClass]
Private Delegate Sub myDelegate()
Private myDelegateInstance As myDelegate
'or you could just leave out 'myDelegate' and use 'System.Action'
Sub New(ByVal MethodEnabled As Integer)
If MethodEnabled = 0 Then
myDelegateInstance = AddressOf Sub0
Else
myDelegateInstance = AddressOf Sub1
End If
End Sub
Sub MyMethod()
myDelegateInstance()
End Sub
Sub Sub0()
'some code here
End Sub
Sub Sub1()
'some code here
End Sub
End Class