Looking for More Efficient Code

RogerSchlueter-7899 1,591 Reputation points
2025-12-28T16:19:19.49+00:00

The following code implements a countdown timer with the time remaining displayed in a TextBox:

Private Sub StartClock(sender As Object, e As RoutedEventArgs) Handles btnStart.Click
    tmr = New Timer(1000) With {.AutoReset = True, .Enabled = True}
    AddHandler tmr.Elapsed, AddressOf UpdateClock
   StartPeriod = << some code that defines the variable in seconds >>
End Sub

Private Sub UpdateClock(source As Object, e As ElapsedEventArgs)
    Dispatcher.Invoke(Sub() PopulateTimer())
End Sub

Private Sub PopulateTimer()
    If StartPeriod > 0 Then
        StartPeriod -= 1
        Dim HourCount As String = (CInt(StartPeriod) \ (60 * 60)).ToString("00:")
        Dim Remainder As Integer = CInt(StartPeriod) Mod (60 * 60)
        Dim MinuteCount As String = (Remainder \ 60).ToString("00:")
        Dim SecondCount As String = (Remainder Mod 60).ToString("00")
        txtRemaining.Text = HourCount & MinuteCount & SecondCount
    Else
        tmr.Stop()
    End If
End Sub


This all works but is too slow so the display is "jerky". Is there a more efficient way to do this?

Windows development | Windows App SDK
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Marcin Policht 73,320 Reputation points MVP Volunteer Moderator
    2025-12-28T18:23:23.84+00:00

    AFAIK, what’s likely making it feel “jerky” isn’t really the string formatting, but rather the combination of System.Timers.Timer firing on a thread-pool thread, marshaling back to the UI thread every tick with Dispatcher.Invoke, and relying on AutoReset timing, which isn’t very precise under load

    Generally, for UI timers in WPF, the recommended approach is to use a DispatcherTimer, which runs directly on the UI thread and integrates with the message pump. In addition, instead of decrementing a counter, you can base the display on actual elapsed time so small delays don’t accumulate.

    Private tmr As DispatcherTimer
    Private endTime As DateTime
    
    Private Sub StartClock(sender As Object, e As RoutedEventArgs) Handles btnStart.Click
        Dim startPeriodSeconds As Integer = 3600 ' for example
    
        endTime = DateTime.Now.AddSeconds(startPeriodSeconds)
    
        tmr = New DispatcherTimer()
        tmr.Interval = TimeSpan.FromSeconds(1)
        AddHandler tmr.Tick, AddressOf UpdateClock
        tmr.Start()
    End Sub
    
    Private Sub UpdateClock(sender As Object, e As EventArgs)
        Dim remaining As TimeSpan = endTime - DateTime.Now
    
        If remaining.TotalSeconds > 0 Then
            txtRemaining.Text = remaining.ToString("hh\:mm\:ss")
        Else
            txtRemaining.Text = "00:00:00"
            tmr.Stop()
        End If
    End Sub
    

    If the above response helps answer your question, remember to "Accept Answer" so that others in the community facing similar issues can easily find the solution. Your contribution is highly appreciated.

    hth

    Marcin

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.