none
How to run task on specified timer from List of Structure RRS feed

  • Question


  • I have a list of structure of two columns (timerMillisec & myfilename). I need to be able to run a separate timer for each row which will open the specified filename according to the Time of its rows.

    The timerMillisec is in millisecond.

    Below is my List of structure and work perfect.

    I'm trying to write a function that will read that list of structure and run each New Timer separately but I couldn't.

    Structure StructCheckTimer
    
            Public timerMillisec As Long
            Public myfileName As String
    
            Public Sub New(ByVal verTime As Long, ByVal verFilename As String)
    
                Me.timerMillisec = verTime
                Me.myfileName = verFilename
    
            End Sub
    
    End Structure
    
    
    Public newStructCheckTimer As New List(Of StructCheckTimer)
    
    newStructCheckTimer.Add(New StructCheckTimer("15000", "c:\myfile1.txt"))
    newStructCheckTimer.Add(New StructCheckTimer("5000", "c:\myfile2.txt"))
    newStructCheckTimer.Add(New StructCheckTimer("20000", "c:\myfile3.txt"))
    ...

    and I read my List of structure using below

    Dim friendsCollection As ICollection = newStructCheckTimer
    
            For Each s As StructCheckTimer In friendsCollection
    
                MsgBox(s.timerMillisec & " -- " & s.myfileName)
    
            Next

    I'm trying to create Function which will read the List of structure and create New Timer of each element using below code but I'm stuck !!!

    Public myTimer As Timer
    
    
        Public Sub StartTimer(ByVal RunTime As Long, ByVal myFile As String)
    
            myTimer = New Timer(RunTime)
            AddHandler _timer.Elapsed, New ElapsedEventHandler(AddressOf Handler)
            myTimer.Enabled = True
    
        End Sub

    you can advise on any other way to do that, I'll appreciate that !!!

    Monday, September 4, 2017 2:56 PM

Answers

  • Christine,

    1. Why you want a Structure, a structure from the size you use is more expensive than using a class. 
    2. Don't use a system timer on a form as you do. A form timer is optimized for that. 

    However, you don't need a class, the problem is simple to solve regarding to your code. 

    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            StartTimer(1000, "c:\myfile1.txt")
            StartTimer(1500, "c:\myfile2.txt")
        End Sub
        Private TimerList As New List(Of Timer)
        Private Sub StartTimer(ByVal RunTime As Integer, ByVal FileName As String)
            TimerList.Add(New Timer With {.Interval = RunTime, .Tag = FileName, .Enabled = True})
            AddHandler TimerList(TimerList.Count - 1).Tick, AddressOf myTimer_Tick
        End Sub
        Private Sub myTimer_Tick(sender As Object, e As EventArgs)
            Dim theUsedTimer = DirectCast(sender, Timer)
            Dim runtime = theUsedTimer.Interval
            Dim filename = theUsedTimer.Tag
            theUsedTimer.Stop()
            
        End Sub
    End Class
    Tested by the way and I used a shorter time duration so I could test


    Success
    Cor




    • Edited by Cor Ligthert Monday, September 4, 2017 5:30 PM
    • Marked as answer by Christine25 Wednesday, September 6, 2017 11:29 AM
    • Unmarked as answer by Christine25 Wednesday, September 6, 2017 3:22 PM
    • Marked as answer by Christine25 Wednesday, September 6, 2017 5:08 PM
    Monday, September 4, 2017 5:28 PM

All replies

  • Christine,

    1. Why you want a Structure, a structure from the size you use is more expensive than using a class. 
    2. Don't use a system timer on a form as you do. A form timer is optimized for that. 

    However, you don't need a class, the problem is simple to solve regarding to your code. 

    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            StartTimer(1000, "c:\myfile1.txt")
            StartTimer(1500, "c:\myfile2.txt")
        End Sub
        Private TimerList As New List(Of Timer)
        Private Sub StartTimer(ByVal RunTime As Integer, ByVal FileName As String)
            TimerList.Add(New Timer With {.Interval = RunTime, .Tag = FileName, .Enabled = True})
            AddHandler TimerList(TimerList.Count - 1).Tick, AddressOf myTimer_Tick
        End Sub
        Private Sub myTimer_Tick(sender As Object, e As EventArgs)
            Dim theUsedTimer = DirectCast(sender, Timer)
            Dim runtime = theUsedTimer.Interval
            Dim filename = theUsedTimer.Tag
            theUsedTimer.Stop()
            
        End Sub
    End Class
    Tested by the way and I used a shorter time duration so I could test


    Success
    Cor




    • Edited by Cor Ligthert Monday, September 4, 2017 5:30 PM
    • Marked as answer by Christine25 Wednesday, September 6, 2017 11:29 AM
    • Unmarked as answer by Christine25 Wednesday, September 6, 2017 3:22 PM
    • Marked as answer by Christine25 Wednesday, September 6, 2017 5:08 PM
    Monday, September 4, 2017 5:28 PM
  • @ Cor Ligthert : I'm taking a look at your code and will reply to you soon.

    @ Frank L. Smith and every one :  What I intend to do is :

    I'm writing a program to send Email message and I store each created message as XML file.

    the program has to send message using two ways (Clicking on Send button) and (Sending it later at a specified time [for ex : send message in 5 min, 15 min, 45 min, 2 hours, 6 hours,... ] it's a REPEAT option, so it will always resend after selected time (x-min / x-hour))

    I'm able to send it right the way by clicking on "Send button", but send the message later, is what's driving me crazy.

    Everything is stored as xml file for each message to be sent (email, cc, object, body, time to send...)

    Note : "Time to send" is not like send the message at a specific time (6:24 PM) NOT !!!), it's instead send after x-minutes or x-hours like I explained above).

    ===

    For me, the algo is as follow : The user create his message and save it in order to be sent later after x-minutes or x-hours.

    I want to create a function which will create new threaded-timer for each message which will open every single xml file at the specified timer interval and add it to a listofMessage to send in order to be sent (like in a queue).

    That is the idea of what I intend to do !!

    Maybe someone can help or advice a better algo to use.

    Thanks in advance !

    Monday, September 4, 2017 6:58 PM
  • Note : "Time to send" is not like send the message at a specific time (6:24 PM) NOT !!!), it's instead send after x-minutes or x-hours like I explained above).

    That will require that you start the timer (and the thread) at the time the message is created, so that when the timer ticks after x-hours and x-minutes the message is sent.  In that case you don't need a queue - the thread is already started, but is dormant until its timer ticks down.

    You should explain why you can't convert the 'time delay' into a 'time to send' by simply adding the delay time to the current time.    That would enable you to create a list of structures, and scan that list at regular intervals to see if a 'time to send' has come around, and if it has then remove that item and process that message.

    Monday, September 4, 2017 9:06 PM
  • You should explain why you can't convert the 'time delay' into a 'time to send' by simply adding the delay time to the current time.    That would enable you to create a list of structures, and scan that list at regular intervals to see if a 'time to send' has come around, and if it has then remove that item and process that message.

    Hi Acamar, you raised a very nice idea/algo, I also thought about that as a second solution if I can't do the first one, the one for the timer.

    By the way, Send Message after x-minutes or x-hours is a REPEAT option which will always send message after specified time until the user disable it.

    The problem I'll face here using this way is, if the user modify the system clock (change hour for instance), what will happen is the message won't be sent; whereas using the Timer, there's no relationship between system clock and Timer so even if the user change the clock, the program will definitely send the message after x-minute / x-hour !!!

    Ex : We're 10:15 AM, and the user schedule to send the message after each 45 minutes, so you add "11:00 AM" in the List of structure to be checked by a Timer...  and the user change his system clock to "12:00 PM" as it was slightly behind. The message will not be sent !!!

    Using this way, I need to constantly go check if user change the system clock !!

    second issue is, assume that you scheduled a message to be sent after each 45 min, using your way (convert "time delay" to "time to send") and you close the program, or shutdown the PC for 2 hours by mistake,  

    then when you launch the program, that message will never be sent as in order to be sent after 45 min, I have to refresh the time to send which is in the List of Structure... I mean synchronize it to the current system time... that's it a long way !!!

    but using Timer for each Message to send after x-minutes / x-hour, even if the program close and restart at later time or date, no need to worry about the system clock, as the Timer will start ticking fresh and fire the event after x-minutes. (better way for me)


    • Edited by Christine25 Tuesday, September 5, 2017 9:11 AM
    Tuesday, September 5, 2017 8:55 AM
  • Cor Ligthert :

    The code you provided gave some errors, it's underlined the below with following message.

    ".Tag" : Tag is not a member of system.timers.timer

    ".Tick" : Tick is not a event of system.timers.timer

    "theUsedTimer.Tag" : Tag is not a member of system.timers.timer

    Tuesday, September 5, 2017 9:01 AM
  • @ Frank L.

    not really getting that very well.

    Tuesday, September 5, 2017 9:02 AM
  • By the way, Send Message after x-minutes or x-hours is a REPEAT option which will always send message after specified time until the user disable it.

    That means that when you pull an event from the list to process and send, you have to put it back into the list with a new calculated send time, based on the send interval.

    The problem I'll face here using this way is, if the user modify the system clock (change hour for instance), what will happen is the message won't be sent.

    Only if you code it that way.  The typical procedure would be to scan the list for everything that is overdue, and send it.   That is essential anyway, because the list scan and send process will take some time, and it is possible that an event time occurs during that process and before the next scanning, so it is actually overdue when that next scan occurs.

    second issue is, assume that you scheduled a message to be sent after each 45 min, using your way (convert "time delay" to "time to send") and you close the program, or shutdown the PC for 2 hours by mistake,  then when you launch the program, that message will never be sent as in order to be sent after 45 min, I have to refresh the time to send which is in the List of Structure.

    Same.  If it's overdue then send it.   You will need to decide whether the next schedule is actual send time + interval, or original scheduled send time + interval, and you might also need code to skip multiple missed overdue sends.  That is, if the send interval was 30m and the machine was shut down for two hours, do you send 4 messages when the machine restarts, or just one?

    but using Timer for each Message to send after x-minutes / x-hour, even if the program close and restart at later time or date, no need to worry about the system clock, as the Timer will start ticking fresh and fire the event after x-minutes. (better way for me)

    Using the timer you won't be able to determine that a message is overdue.  So if the send interval is three hours, and after the first hour the machine is shut down for two hours, then how long after restart will the message be sent?   With a ticking timer it will be either two hours (if you can keep track of the time already ticked off) or three hours (if the timer restarts from zero), when in fact the  machine was up and running at the original scheduled send time.


    • Edited by Acamar Tuesday, September 5, 2017 10:08 AM sp
    Tuesday, September 5, 2017 10:07 AM
  • Thanks User Acamar !!!

    So, Please which way should I go for??  

    but honestly I prefer the Timer way as I'll code less.

    and for now, I don't need to worry about Messages that are not sent due to PC shutdown,

    what I need to focus is to be able to easily send message after x-minutes / x-hours repeatedly... and If the system was off, when it starts it will just run each Timer according to the original time instead of doing many calculation for how long the system has been off and son on.

    For that, I prefer to use Timer for each message to send.

    • Edited by Christine25 Tuesday, September 5, 2017 10:31 AM
    Tuesday, September 5, 2017 10:20 AM
  • Cor Ligthert :

    The code you provided gave some errors, it's underlined the below with following message.

    ".Tag" : Tag is not a member of system.timers.timer

    ".Tick" : Tick is not a event of system.timers.timer

    "theUsedTimer.Tag" : Tag is not a member of system.timers.timer

    That I wrote, why do you use a system timer. That one is for a service but then you cannot use the messagebox. 

    The Windows Forms Timer is the best for a windows forms, a threading timer for threading and a dispatcher timer for WPF.


    Success
    Cor

    Tuesday, September 5, 2017 10:23 AM
  • Thanks Cor Ligthert.

    I didn't even realize that there was "Imports System.Timers" on top !!!

    I took it out and it cleared the underline.

    Let me try it and will get back to you, please !!

    Thanks in advance !

    Tuesday, September 5, 2017 10:35 AM
  • @ Cor Ligthert.

    sorry, what does the code do??? as I ran it and does nothing !!

    Did I miss anything??

    Tuesday, September 5, 2017 10:40 AM
  • @ Cor Ligthert.

    sorry, what does the code do??? as I ran it and does nothing !!

    Did I miss anything??

    That depends what you want to do. 

    If you change this 

      
            Dim filename = theUsedTimer.Tag

    For 

    process.start(Cstr(theUsedTimer.Tag))
    
    
    And put in that string that you put in the Tag a full path to the program it will start that program.


    Success
    Cor

    Tuesday, September 5, 2017 10:52 AM
  • @ Cor.

    Thanks, that's really what I wanted but Please can you help me modify that code a little bit.

    As I explained on my first post that I use a List of structure of two columns.

    So, StartTimer(6000, "c:\myfile1.txt") will take those values (millisec and filename) from the above list of structure. (How do I do that) ??

    and

    all the Timers must NOT STOP after it fires as they are repeated TASK (until user disable it from the file)

    and seems like (TimerList(TimerList.Count - 1)) take out the item from the list, whereas I don't need to delete item from the List, as it's a repeat task.

    and If a user schedule a message to be sent after each (4.5 hours) for instance, how do i convert it in millisecond in order to put it in the List of structure.

    How do I achieve them??

    Thanks in advance !!!

    Tuesday, September 5, 2017 12:06 PM
  • @ Cor,

    I managed to feed StartTimer from the List of Structure and works well.

    I also disable the Timer to stop after firing.

    What does TimerList(TimerList.Count - 1)  do ??

    and how to convert like (4.5 hours) to millisecond and what TYPE should I use to store that variable (Integer, Long, Double,...)?

    As the biggest amount that "timerMillisec" variable will hold is "24 hours" which need to be convert in minutes (1440 minutes) which also need to convert in second ( 86400 seconds) which also need to be convert in millisecond (86 400 000)

    So which type (86 400 000 ) can fit on?? Integer or Long ??


    • Edited by Christine25 Tuesday, September 5, 2017 1:49 PM
    Tuesday, September 5, 2017 12:51 PM
  • @ Cor,

    I managed to feed StartTimer from the List of Structure and works well.

    I also disable the Timer to stop after firing.

    What does TimerList(TimerList.Count - 1)  do ??

    and how to convert like (4.5 hours) to millisecond and what TYPE should I use to store that variable (Integer, Long, Double,...)?

    As the biggest amount that "timerMillisec" variable will hold is "24 hours" which need to be convert in minutes (1440 minutes) which also need to convert in second ( 86400 seconds) which also need to be convert in millisecond (86 400 000)

    So which type (86 400 000 ) can fit on?? Integer or Long ??


    Christine, 

    Often I start talking about the solution, which does not go in my perception. I see than others answer it as it was asked. I did that currently, knowing that it never would reach production. 

    Your problem is in fact a scheduler problem. 

    We have it as solution on our website. There is used a DataTable, not because it is a database, but because that can so easily be saved to disk. 

    Take a look at it,

    http://www.vb-tips.com/WindowsFormsSchedulerDataGridView.ASPX


    Success
    Cor

    Tuesday, September 5, 2017 2:51 PM
  • I'm using it in production and works perfect.

    Only 3 sec which is to short. (Not so bad !!!)

    My application is not using seconds, it uses minutes and hour instead.

    So 11h45:1 sec until 11h45:59 sec is still 11h45 min NOT 11h46 min which is Good for me as the program doesn't worry about seconds, only hour and minutes that we need. 

    and Sending a Message is a background task in this program, so the user will not be aware of that !!

    even the link you provided also has 3 sec to short !!

    I appreciate that you introduce me "DataTable" that I didn't know before starting the project... which could have saved me a lot of time if I had used it in my application as now I use a List Of Structure to store user scheduler "date & time" which needs to be checked by the Timer.


    My application is 95 % completed so I can't rewrite it only to use DataTable !!

    I'll use it in the next application if it requires a scheduler.

    Thanks !!




    • Edited by Christine25 Wednesday, September 6, 2017 11:24 AM
    Wednesday, September 6, 2017 11:16 AM
  • @ Cor :

    How do I remove a item from TimerLIst ? I tried below code but has not worked !!

    TimerList.Remove(New Timer With {.Interval = "15000", .Tag = "c:\myfile2.txt", .Enabled = True})


    Wednesday, September 6, 2017 1:06 PM
  • or

    How do I stop one TimerList which has .Tag = "c:\myfile2.txt" ?

    Wednesday, September 6, 2017 3:22 PM
  • or

    How do I stop one TimerList which has .Tag = "c:\myfile2.txt" ?

    It is included the last sample. 

       Private Sub myTimer_Tick(sender As Object, e As EventArgs)
            Dim theUsedTimer = DirectCast(sender, Timer)
            Dim runtime = theUsedTimer.Interval
            Dim filename = theUsedTimer.Tag
            theUsedTimer.Stop()
            
        End Sub


    Success
    Cor

    Wednesday, September 6, 2017 4:20 PM
  • Thanks so much Cor.
    Wednesday, September 6, 2017 5:09 PM