3
\$\begingroup\$

This code (Windows Forms) shows a series of timers so that the user can manually time a series of tasks. I decided to put this together today because next weekend I want to go through an activity (about 4-5 distinct tasks) and see how long it takes.

The main window is where all the action takes place. enter image description here

The task buttons are a custom control (label, button, button, label) in a flow panel. The window expands as more tasks are added. The "Add Task" button asks for the task name before inserting a custom control in the panel.

All the time displays are updated based on a common timer. In addition, an individual time display is updated when that timer is stopped. For some slight added efficiency, the time displays are only updated when the timer is on - handlers are removed otherwise. Each timer is a 'one-off', there is no restarting or pausing - this is by design.

This works as I expected. If I were to create a more commercial product, then I would add some more features and probably double check any error handling/potential error conditions. I know that cancelling the input on entering a task will still give me a task (something that I would tidy up if I were going to share it) but it still works as intended (after all I don't have to start a timer if I don't want to!).

Custom Control - individual task timer

enter image description here

Public Class ctlTaskTimer
    Private pThisTaskTimer As TaskTimer

    Public ReadOnly Property ThisTaskTimer() As TaskTimer
        Get
            Return pThisTaskTimer
        End Get
    End Property

    Public Sub UpdateTime()
        lblTime.Text = pThisTaskTimer.ElapsedTime.ToString("hh\:mm\:ss")
    End Sub

    Private Sub btnTimerStart_Click(sender As Object, e As EventArgs) Handles btnTimerStart.Click
        StartTimer()
    End Sub

    Private Sub btnTimerStop_Click(sender As Object, e As EventArgs) Handles btnTimerStop.Click
        StopTimer()
    End Sub

    Public Sub New(TaskName As String)
        ' This call is required by the designer.
        InitializeComponent()
        ' Add any initialization after the InitializeComponent() call.
        pThisTaskTimer = New TaskTimer(TaskName)
        lblTaskName.Text = TaskName
        btnTimerStop.Enabled = False
    End Sub

    Public Sub StartTimer()
        If Not pThisTaskTimer.Running Then
            pThisTaskTimer.StartTimer()
            btnTimerStart.Enabled = False
            btnTimerStop.Enabled = True
            AddHandler TaskTimerMain.DoRefreshTime, AddressOf UpdateTime
        End If
    End Sub

    Public Sub StopTimer()
        If pThisTaskTimer.Running Then
            pThisTaskTimer.StopTimer()
            btnTimerStart.Enabled = False ' single use control.
            btnTimerStop.Enabled = False
            UpdateTime()
            RemoveHandler TaskTimerMain.DoRefreshTime, AddressOf UpdateTime
        End If
    End Sub
End Class

Main Window - the user application interface

enter image description here

Public Class TaskTimerMain

    Event DoRefreshTime()
    Private ptimer As New Windows.Forms.Timer()

    Private Sub btnAddTask_Click(sender As Object, e As EventArgs) Handles btnAddTask.Click
        Dim tName As String = InputBox("Enter a Name for the Task", "Task Entry", "<Name>")
        ctlTimerControls.Controls.Add(New ctlTaskTimer(tName))
    End Sub

    Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
        RemoveHandler ptimer.Tick, AddressOf timer_Tick
        Application.Exit()
    End Sub

    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()
        ' Add any initialization after the InitializeComponent() call.
        ptimer.Interval = (1 * 1000)  ' update every second
        AddHandler ptimer.Tick, AddressOf timer_Tick
        ptimer.Start()
    End Sub

    Private Sub timer_Tick(sender As Object, e As EventArgs)
        RaiseEvent DoRefreshTime()
    End Sub

    Private Sub btnStartAll_Click(sender As Object, e As EventArgs) Handles btnStartAll.Click
        For Each ctl As ctlTaskTimer In ctlTimerControls.Controls
            ctl.StartTimer()
        Next
    End Sub

    Private Sub btnStopAll_Click(sender As Object, e As EventArgs) Handles btnStopAll.Click
        For Each ctl As ctlTaskTimer In ctlTimerControls.Controls
            ctl.StopTimer()
        Next
    End Sub
End Class

The task timer class

I set this as a separate class rather than encapsulate it in the custom control. This separates the core data from the presentation and allows the task timer class to be re-used if I wanted.

Public Class TaskTimer

    Private pName As String = "<Name>"
    Private pTimeStart As DateTime = DateTime.Now
    Private pTimeEnd As DateTime = DateTime.Now
    Private pRunning As Boolean = False

    ReadOnly Property Name As String
        Get
            Return pName
        End Get
    End Property
    ReadOnly Property ElapsedTime As TimeSpan
        Get
            Return If(pRunning, DateTime.Now.Subtract(pTimeStart), pTimeEnd.Subtract(pTimeStart))
        End Get
    End Property
    ReadOnly Property Running As Boolean
        Get
            Return pRunning
        End Get
    End Property

    Public Sub New(TaskName As String)
        pName = TaskName
        pRunning = False
    End Sub

    Sub StartTimer()
        If Not Me.Running Then
            pTimeStart = DateTime.Now
            pRunning = True
        End If
        ' ignore if try to start when already running
    End Sub

    Sub StopTimer()
        If Me.Running Then
            pTimeEnd = DateTime.Now
            pRunning = False
        End If
        ' ignore if try to stop when already stopped
    End Sub
End Class
\$\endgroup\$
  • \$\begingroup\$ I would suggest that rather than create a completely new Timer, you can inherit all the functionality that you have at the moment from the StopWatch class apart from the name which you can add yourself into your Timer class \$\endgroup\$ – David Wilson Jun 13 '18 at 11:18
  • \$\begingroup\$ @DavidWilson: Did you want to turn that into an answer? This is code review, after all :-) \$\endgroup\$ – AJD Jun 13 '18 at 19:30
  • \$\begingroup\$ @DavidWilson ... noting that it is not just the timer it self, but also the custom control. That I might extend it provides some context for a review (but of course, you cannot review non-existent code). \$\endgroup\$ – AJD Jun 13 '18 at 19:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.