I want to make a variable that can count up from 0 in milliseconds
I don't want to use the timer from the Toolbox, but build it with code.
So far I declared a timer object, but how do I bind it to an Event that can convert the time into a counter and append it to a variable?
See below what I tried so far, but without success
Imports System.Timers
Public Class Counter
Property Count As Integer
Private Sub Counter_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Count = Counter()
Console.WriteLine(Count)
End Sub
Public Function Counter() As Integer
' Create timer
Dim timer As Timer = New Timer()
timer.Interval = 1000
'AddHandler timer.Elapsed, AddressOf TimerEvent
timer.AutoReset = True
timer.Enabled = True
Return Integer.Parse(timer.ToString())
End Function
Private Sub CountEvent(ByVal source As Object, ByVal e As ElapsedEventArgs)
'Console.WriteLine("Event Raised at {0:HH:mm:ss.fff}", e.SignalTime)
'Console.WriteLine("Count Miliseconds {0:fff}", e.SignalTime) ' count milisecond
Console.WriteLine("Count Seconds {0:ss}", e.SignalTime) ' count milisecond
End Sub
End Class
I hope my code below will help you. It will run as-is in a console app, but you just need to extract the Counter class.
Imports System.Timers
Module Module1
Dim oCounter As Counter
Sub Main()
oCounter = New Counter(1000)
AddHandler oCounter.Count, AddressOf Counter_Count
Console.WriteLine("You can press any key to quit after 10,000 milliseconds.")
oCounter.StartCounter()
While oCounter.TotalMillisecondsPassed < 10000
Console.ReadKey()
End While
End Sub
Sub Counter_Count(Sender As Object, TotalMillisecondsPassed As Long)
Console.WriteLine(TotalMillisecondsPassed & " milliseconds passed since: " & oCounter.StartTime.ToString("dd/MM/yyyy HH:mm:ss:fff"))
End Sub
' A class to keep track of the number of milliseconds passed since the
' Timer was initiated and to raise an event every x number of milliseconds
Private Class Counter
' The time the Counter was started
Public ReadOnly Property StartTime As Date
Get
Return MyStartTime
End Get
End Property
' The total number of milliseconds that have passed
Public ReadOnly Property TotalMillisecondsPassed As Long
Get
Return (Date.Now - MyStartTime).TotalMilliseconds
End Get
End Property
' The event is raised each time the interval has passed
Public Event Count(Sender As Object, TotalMillisecondsPassed As Long)
Private MyStartTime As Date
Private oTimer As Timer
' The interval between Count events
Public Sub New(IntervalInMillisenconds As Integer)
oTimer = New Timer(IntervalInMillisenconds)
AddHandler oTimer.Elapsed, AddressOf TimerElapsed
oTimer.AutoReset = True
End Sub
' Starts the counter
Public Sub StartCounter()
MyStartTime = Date.Now()
oTimer.Start()
End Sub
' Stops the counter
Public Sub StopCounter()
oTimer.Stop()
End Sub
' Handles the internal event of the timer elapsing
Private Sub TimerElapsed(ByVal source As Object, ByVal e As ElapsedEventArgs)
RaiseEvent Count(Me, TotalMillisecondsPassed)
End Sub
End Class
End Module
I solved it
Dim Counter As Integer
Private Sub TimerEvent(ByVal source As Object, ByVal e As ElapsedEventArgs)
' Count Up
If 1 <> 2 Then
Counter = Counter + 1
End If
Console.WriteLine("Count Up: " & Counter)
End Sub
Related
Issue
I am using multi-threading inside my application and the way it works is that i have an array that contains 22 string which stand for some file names:
Public ThreadList As String() = {"FSANO1P", "FJBJB1P", "COPOR1P", "FFBIVDP", "FFCHLDP", "FFDBKDP", "FFDREQP", "FFINVHP", "FFJMNEP", "FFPIVHP", "FFUNTTP", "FJBJM1P", "FJBJM2P", "FJBNT2P", "FPPBE9P", "FTPCP1P", "FTTEO1P", "FTTRQ1P", "FJBJU1P", "FTTEG1P", "FFJACPP", "XATXTDP"}
I then loop through the array and create a new thread for each file:
For Each mThreadName As String In ThreadList
Dim mFileImportThread = New FileImportThreadHandling(mThreadName, mImportGuid, mImportDate, Directory_Location, mCurrentProcessingDate, mRegion)
Next
So inside the new thread 'FileImportThreadHandling' it will call a method by starting a new thread:
mThread = New Thread(AddressOf DoWork)
mThread.Name = "FileImportThreadHandling"
mThread.Start()
Then in 'DoWork' it will determine what file is current in question and will run the code related to the file.
After the code has ran for the file I want to report this back to the main thread. Can somebody give me a solution please.
You will need to use Delegates
EDIT:
Take a look at this snippet:
Sub Main()
mThread = New Thread(AddressOf doWork)
mThread.Name = "FileImportThreadHandling"
mThread.Start()
End Sub
Sub doWork()
'do a lot of hard work
workDone(result)
End Sub
Delegate Sub workDoneDelegate(result As Integer)
Sub workDone(abilita As Boolean, Optional src As Control = Nothing)
If Me.InvokeRequired Then
Me.Invoke(New workDoneDelegate(AddressOf workDone), {result})
Else
'here you're on the main thread
End If
End Sub
Here is an example that might give you some ideas. Note the use of Async and Task. You will need a form with two buttons, and a label.
Public Class Form1
Public ThreadList As String() = {"FSANO1P", "FJBJB1P", "COPOR1P", "FFBIVDP", "*******", "FFJACPP", "XATXTDP"}
'note Async keyword on handler
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Button1.Enabled = False
Dim running As New List(Of Task)
For Each tskName As String In ThreadList
'start new task
Dim tsk As Task
tsk = Task.Run(Sub()
For x As Integer = 1 To 10
Dim ct As Integer = x
'simulate code related to the file
Threading.Thread.Sleep(500)
'report to the UI
Me.Invoke(Sub()
Label1.Text = String.Format("{0} {1}", tskName, ct)
End Sub)
Next
End Sub)
Threading.Thread.Sleep(100) 'for testing delay between each start
running.Add(tsk)
Next
'async wait for all to complete
For Each wtsk As Task In running
Await wtsk
Next
Button1.Enabled = True
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
'test UI responsive during test
Label1.Text = DateTime.Now.ToString
End Sub
End Class
Using Actions and a callback to track remaining operations. (Simplified your class for my example)
Public ThreadList As String() = {"FSANO1P", "FJBJB1P", "COPOR1P", "FFBIVDP", "FFCHLDP"}
Private actionCounter As Integer = 0
Private lockActionCounter As New Object()
Sub Main()
Console.WriteLine("Starting...")
For Each mThreadName As String In ThreadList
Dim mFileImportThread = New FileImportThreadHandling(mThreadName)
actionCounter += 1
Call New Action(AddressOf mFileImportThread.DoWork).
BeginInvoke(AddressOf callback, mThreadName)
Next
Console.Read()
End Sub
Private Sub callback(name As IAsyncResult)
Dim remainingCount As Integer
SyncLock lockActionCounter
actionCounter -= 1
remainingCount = actionCounter
End SyncLock
Console.WriteLine("Finished {0}, {1} remaining", name.AsyncState, actionCounter)
If remainingCount = 0 Then Console.WriteLine("All done")
End Sub
Private Class FileImportThreadHandling
Shared r = New Random()
Private _name As String
Public Sub New(name As String)
_name = name
End Sub
Public Sub DoWork()
Dim delayTime = (r).Next(500, 5000)
Console.WriteLine("Doing {0} for {1:0}ms.", _name, delayTime)
Thread.Sleep(delayTime)
End Sub
End Class
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
I want some values in a class to decrease whenever the timer in the main form ticks. I am creating multiple instances of the same class as my program is a simulation application and I am not storing these instances in an array or any list in that matter. I simply declare them and add their picture box to the controls on the main form. However I am hoping to have a sub routine inside the class that triggers whenever the timer in the main form ticks. I thought of something like this:
Public Class Jimmy
Dim _a As Integer = 10
Sub decreseNum(sender As Object, e As EventArgs) Handles mainapp.tmrLog.Tick
_a -= 1
End Sub
End Class
with mainapp being the name of the main form and tmrLog being the timer I want to associate my sub routine with. However the above code doesn't work
You could try defining a local reference to the timer in the Jimmy class:
Public Class Jimmy
Dim _a As Integer = 10
Private WithEvents tmr As Timer
Public Sub New(ByRef MainTmr As Timer)
tmr = MainTmr
End Sub
Sub decreseNum(sender As Object, e As EventArgs) Handles tmr.Tick
_a -= 1
End Sub
End Class
If you want all your classes react to timer.elapsed event, just sign up for it. The program below is fully operational. It is example what you can do to have your children to react to timer events of single parent/timer
Imports System
imports system.timers
Public Module Module1
Public Sub Main()
dim mc as new MainClass()
mc.CreateChildren(5)
System.Threading.Thread.Sleep(60000) ' wait and monitor output of childern
mc.Stop()
Console.WriteLine("All should stop now...")
Console.Read()
End Sub
End Module
public class MainClass 'This class could be your form
private _timer as new Timer(5000)
public sub CreateChildren(count as integer)
For i as integer = 1 to count
dim c as new Child(i)
Addhandler _timer.Elapsed, addressof c.DoWhentimerTicks
next
Console.WriteLine("timer should run now...")
_timer.Start()
end sub
public sub [Stop]()
_timer.Stop()
End Sub
End class
public class Child
private _myNO as integer
public sub new (no as integer)
_myNo = no
end sub
public sub DoWhentimerTicks(sender as object , e as ElapsedEventArgs)
Console.WriteLine(string.format("Child #{0} just ticked. Time = {1}", _myNo, e.signaltime))
end sub
End class
I found my solution, posting here for further reference.
My situation was trying to have my timer in the mainform triggering a sub in a class, and I used the following solution.
Class:
Sub addHandlesToSub
AddHandler Form1.Timer1.Tick, AddressOf subToBeTriggered
End Sub
Sub subToBeTriggered(sender As Object, e As EventArgs)
'My code
End Sub
The parameters in subToBeTriggered are useful when you want to remove the handler with
RemoveHandler Form1.Timer1.Tick, AddressOf subToBeTriggered
Otherwise, there will be an error without the parameters.
Thanks for all the answers though.
I've defined a SerialPort object as the following:
Public WithEvents SerialComm As New System.IO.Ports.SerialPort
SerialComm is setup and opened in the object constructor and closed when the object is disposed. My handler signature is as follows:
Private Sub OnComm(sender as Object, e as SerialDataReceivedEventArgs) Handles SerialComm.DataReceived
I'm trying to get a DataReceived event to fire from HyperTerminal. After sending some data, I can set a breakpoint and check the value of SerialComm.BytesToRead and see that it has updated to the proper number of bytes.
I have confirmed that the SerialPort is open and is receiving data, but I can't get the event to fire.
I've also tried manually wiring up the event (after removing the WithEvents definition) using AddHandler, but I was still unable to get the event to trigger.
What am I missing?
Update:
This is the class that I'm having trouble with:
Imports System.IO.Ports
Public Class CopyCat
Implements IDisposable
Private RxString As String
Private LastReceiveTime As DateTime
Public WithEvents SerialComm As New SerialPort
Public Property Timeout As TimeSpan
Public Sub New(commPort As String, timeout As TimeSpan)
Me.Timeout = timeout
Enable(commPort)
End Sub
Public Sub New(commPort As String)
Me.New(commPort, TimeSpan.FromMilliseconds(1000))
End Sub
Public Sub Enable()
CommUtilities.SetupComm(SerialComm, commPort, 115200, 8, Parity.Odd, StopBits.One, Handshake.None, System.Text.Encoding.Default)
End Sub
Public Sub Disable()
SerialComm.Close()
End Sub
Private Sub OnComm(sender As Object, e As SerialDataReceivedEventArgs) Handles SerialComm.DataReceived
If(DateTime.Now - LastReceivedTime > Timeout) Then RxString = ""
Do While(SerialComm.BytesToRead > 0)
Dim readChar As String
Dim termChar As Char = Chr(RxString.ToByteList().XorAll())
readChar = SerialComm.ReadChar
RxString &= readChar
if (readChar = termChar) Then
SerialComm.Write((From item In GetResponse(RxString).Build()
Select item.Data).ToRawString)
RxString = ""
End If
Loop
End Sub
Public Function GetResponse(commandString As String) As MessageResponse
Dim response As MessageResponse = MessageResponse.GetMessageResponseFromByteList(commandString.ToByteList())
if (response.GetType = GetType(GetStatusResponse)) Then
response.DataBytes(8).Data = Math.Floor(Rnd() * 255)
response.DataBytes(9).Data = Math.Floor(Rnd() * 255)
End If
Return response
End Function
Private disposedValue as Boolean
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
SerialComm.Dispose()
End If
End If
Me.disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
End Class
After program execution, the extension that the FileStream uses is the default one provided in the Class header instead of the one i specified via the "set property".
How come it never changed?
Form1.vb Code
Option Strict On
Imports S3_BalanceBook_Dayan.Wallet
Public Class Form1
Dim myWallet As New Wallet(DataGridView1, DateTimePicker1)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Make default selection when program starts.
optCheck.Checked = True
myWallet.StatementsFileName = "statements.dat"
DataGridView1.Rows.Add(New String() {"12/21/1986", "Test", "44554", "44.22", "45.12"})
End Sub
Private Sub cmdAddTransaction_Click(sender As System.Object, e As System.EventArgs) Handles cmdAddTransaction.Click
If optCheck.Checked Then
lblAvailableFunds.Text = FormatCurrency(myWallet.Check(CInt(Trim(txtCheck.Text)), _
CDec(Trim(txtMoney.Text))))
End If
End Sub
Private Sub optDeposit_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles optDeposit.CheckedChanged
'Disable un-needed fields when Deposit Radio button is selected!
txtCheck.Enabled = False
txtMoney.Enabled = False
txtDeposit.Enabled = True
txtFee.Enabled = False
txtDescription.Enabled = True
End Sub
Private Sub optCheck_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles optCheck.CheckedChanged
'Disable un-needed fields when Check Radio button is selected!
txtCheck.Enabled = True
txtMoney.Enabled = True
txtDeposit.Enabled = False
txtFee.Enabled = False
txtDescription.Enabled = True
End Sub
Private Sub optServiceFee_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles optServiceFee.CheckedChanged
'Disable un-needed fields when Fee Radio button is selected!
txtCheck.Enabled = False
txtMoney.Enabled = False
txtDeposit.Enabled = False
txtFee.Enabled = True
txtDescription.Enabled = True
End Sub
End Class
Wallet.vb Code
Option Strict On
Imports System
Imports System.IO
Public Class Wallet
Private lcheckNumber As Integer = Nothing
Private lcheckmoney As Decimal = Nothing
Private ldepositAmount As Decimal = Nothing
Private lfee As Decimal = Nothing
Private holdInstance As DataGridView
Private holdDate As DateTimePicker
Private holdPath As String = "default.txt"
Private _file As New FileStream(holdPath, FileMode.OpenOrCreate, FileAccess.ReadWrite)
Private file As New StreamWriter(_file)
'Default Constructor
Public Sub New()
End Sub
Public Sub New(ByRef Data As DataGridView, ByRef StatementDate As DateTimePicker)
'This constructor takes in references to use in class as private
holdInstance = Data
holdDate = StatementDate
End Sub
''' <summary>
''' Property allows the change of file path for the statements log.
''' </summary>
Public WriteOnly Property StatementsFileName() As String
Set(ByVal Value As String)
holdPath = Value
End Set
End Property
''' <summary>
''' Enter Deposit amount as Decimal, returns remainding account balance as Decimal.
''' </summary>
Public Function Deposit(ByVal Amount As Decimal) As Decimal
Return 0D
End Function
'Function Check - Deduct the amount and returns current balance.
Public Function Check(ByVal CheckNumber As Integer, ByVal CheckAmount As Decimal) As Decimal
Try
file.WriteLine(CheckNumber & " - " & CheckAmount)
Catch e As IOException
MessageBox.Show(e.ToString)
End Try
Return 0D
End Function
'Function Fee - Deduct the fee from balance and returns current balance.
Public Function Fee(ByVal FeeAmount As Decimal) As Decimal
Return 0D
End Function
End Class
Yup - it's here that the problem is:
Private holdPath As String = "default.txt"
Private _file As New FileStream(holdPath, FileMode.OpenOrCreate, FileAccess.ReadWrite)
Private file As New StreamWriter(_file)
That will initialize _file with the value of holdPath, at the point at which the Wallet instance is created. Instead of having _file and file as member fields, why not make them local variables inside Check? That way, when they're constructed, they'll use the value of holdPath, as it is at that time.
You should also, probably, put them inside Using statements, or otherwise ensure that they're closed at a suitable point - otherwise, the contents you write to the file may not appear until your program is closed.
So, we'd have:
Public Function Check(ByVal CheckNumber As Integer, ByVal CheckAmount As Decimal) As Decimal
Try
Using _file As New FileStream(holdPath, FileMode.OpenOrCreate, FileAccess.ReadWrite)
Using file As New StreamWriter(_file)
file.WriteLine(CheckNumber & " - " & CheckAmount)
End Using
End Using
Catch e As IOException
MessageBox.Show(e.ToString)
End Try
Return 0D
End Function