Si a todo esto también necesitas una solución completa para implementar ya sea un cronómetro o una cuenta atrás, aquí tienes una solución que ideé hace tiempo (nuevamente sacada de mi librería de clases ElektroKit):
+
+
Tendrías que editar las classes de arribas un poquito para eliminarle el código sobrante, es decir los espacios de nombres y los imports de la librería y creo que nada más.
El modo de empleo para implementarlo a modo de cuenta atrás, sería más o menos el siguiente:
Si tienes cualquier duda al respecto del código, tan solo pregunta.
Saludos!.
Código (vbnet) [Seleccionar]
' ***********************************************************************
' Author : Elektro
' Modified : 12-December-2015
' ***********************************************************************
#Region " Public Members Summary "
#Region " Constructors "
' New()
#End Region
#Region " Events "
' TimeUpdated(Object, TimeMeasurerUpdatedEventArgs)
#End Region
#Region " Properties "
' MaxValue As Double
' State As TimeMeasurerState
' UpdateInterval As Integer
#End Region
#Region " Methods "
' Start(Double)
' Start(Date, Date)
' Start(TimeSpan)
' Pause()
' Resume()
' Stop()
' Dispose()
#End Region
#End Region
#Region " Usage Examples "
#End Region
#Region " Option Statements "
Option Strict On
Option Explicit On
Option Infer Off
#End Region
#Region " Imports "
Imports System.ComponentModel
Imports System.Windows.Forms
' Imports Elektro.Core.DateAndTime.Enums
' Imports Elektro.Core.DateAndTime.Types.EventArgs
' Imports Elektro.Core.Types
#End Region
#Region " Time Measurer "
Namespace DateAndTime.Types
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Measures the elapsed and/or remaining time of a time interval.
''' The time measurer can be used as a chronometer or a countdown.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
<ImmutableObject(False)>
Public NotInheritable Class TimeMeasurer : Implements IDisposable ': Inherits AestheticObject
#Region " Private Fields "
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' An <see cref="Stopwatch"/> instance to retrieve the elapsed time. (a chronometer)
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Private timeElapsed As Stopwatch
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' A <see cref="TimeSpan"/> instance to retrieve the remaining time. (a countdown)
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Private timeRemaining As TimeSpan
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' A <see cref="Timer"/> instance that updates the elapsed and remaining time,
''' and also raise <see cref="TimeMeasurer"/> events.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Private WithEvents measureTimer As Timer
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Flag that indicates wheter this <see cref="TimeMeasurer"/> instance has finished to measure time interval.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Private isFinished As Boolean
#End Region
#Region " Properties "
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets the maximum time that the <see cref="TimeMeasurer"/> can measure, in milliseconds.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <value>
''' The maximum time that the <see cref="TimeMeasurer"/> can measure, in milliseconds.
''' </value>
''' ----------------------------------------------------------------------------------------------------
Public Shared ReadOnly Property MaxValue As Double
<DebuggerStepThrough>
Get
Return (TimeSpan.MaxValue.TotalMilliseconds - 1001.0R)
End Get
End Property
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets the current state of this <see cref="TimeMeasurer"/> instance.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <value>
''' The current state of this <see cref="TimeMeasurer"/> instance.
''' </value>
''' ----------------------------------------------------------------------------------------------------
Public ReadOnly Property State As TimeMeasurerState
<DebuggerStepThrough>
Get
If (Me.timeElapsed Is Nothing) OrElse (Me.isFinished) Then
Return TimeMeasurerState.Disabled
ElseIf Not Me.timeElapsed.IsRunning Then
Return TimeMeasurerState.Paused
Else
Return TimeMeasurerState.Enabled
End If
End Get
End Property
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets or sets the update interval.
''' Maximum value is 1000 (1 second).
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <value>
''' The update interval.
''' </value>
''' ----------------------------------------------------------------------------------------------------
''' <exception cref="ArgumentException">
''' A value smaller than 1000 is required.;value
''' </exception>
Public Property UpdateInterval As Integer
<DebuggerStepThrough>
Get
Return Me.updateIntervalB
End Get
<DebuggerStepThrough>
Set(ByVal value As Integer)
If (value > 1000) Then
Throw New ArgumentException(message:="A value smaller than 1000 is required.", paramName:="value")
Else
Me.updateIntervalB = value
If (Me.measureTimer IsNot Nothing) Then
Me.measureTimer.Interval = value
End If
End If
End Set
End Property
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' ( Backing field )
''' The update interval.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Private updateIntervalB As Integer = 100I
#End Region
#Region " Events "
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Occurs when the elapsed/remaining time updates.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Public Event TimeUpdated(ByVal sender As Object, ByVal e As TimeMeasurerUpdatedEventArgs)
#End Region
#Region " Constructors "
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Initializes a new instance of the <see cref="TimeMeasurer"/> class.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Sub New()
End Sub
#End Region
#Region " Public Methods "
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Starts the time interval measurement.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <param name="milliseconds">
''' The time interval to measure, in milliseconds.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <exception cref="ArgumentOutOfRangeException">
''' milliseconds;A value smaller than <see cref="TimeMeasurer.MaxValue"/> is required.
''' </exception>
'''
''' <exception cref="ArgumentOutOfRangeException">
''' milliseconds;A value greater than 0 is required.
''' </exception>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Sub Start(ByVal milliseconds As Double)
If (milliseconds > TimeMeasurer.MaxValue) Then
Throw New ArgumentOutOfRangeException(paramName:="milliseconds",
message:=String.Format("A value smaller than {0} is required.", TimeMeasurer.MaxValue))
ElseIf (milliseconds <= 0) Then
Throw New ArgumentOutOfRangeException(paramName:="milliseconds",
message:="A value greater than 0 is required.")
Else
Me.timeElapsed = New Stopwatch
Me.timeRemaining = TimeSpan.FromMilliseconds(milliseconds)
Me.measureTimer = New Timer With
{
.Tag = milliseconds,
.Interval = Me.updateIntervalB,
.Enabled = True
}
Me.isFinished = False
Me.timeElapsed.Start()
Me.measureTimer.Start()
End If
End Sub
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Starts a time interval measurement given a difference between two dates.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <param name="startDate">
''' The starting date.
''' </param>
'''
''' <param name="endDate">
''' The ending date.
''' </param>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Sub Start(ByVal startDate As Date,
ByVal endDate As Date)
Me.Start(endDate.Subtract(startDate).TotalMilliseconds)
End Sub
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Starts a time interval measurement given a <see cref="TimeSpan"/>.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <param name="time">
''' A <see cref="TimeSpan"/> instance that contains the time interval.
''' </param>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Sub Start(ByVal time As TimeSpan)
Me.Start(time.TotalMilliseconds)
End Sub
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Pauses the time interval measurement.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <exception cref="Exception">
''' TimeMeasurer is not running.
''' </exception>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Sub Pause()
If (Me.State <> TimeMeasurerState.Enabled) Then
Throw New Exception("TimeMeasurer is not running.")
Else
Me.measureTimer.Stop()
Me.timeElapsed.Stop()
End If
End Sub
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Resumes the time interval measurement.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <exception cref="Exception">
''' TimeMeasurer is not paused.
''' </exception>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Sub [Resume]()
If (Me.State <> TimeMeasurerState.Paused) Then
Throw New Exception("TimeMeasurer is not paused.")
Else
Me.measureTimer.Start()
Me.timeElapsed.Start()
End If
End Sub
''' <summary>
''' Stops the time interval measurement.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <exception cref="Exception">
''' TimeMeasurer is not running.
''' </exception>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Sub [Stop]()
If (Me.State = TimeMeasurerState.Disabled) Then
Throw New Exception("TimeMeasurer is not running.")
Else
Me.Reset()
Me.isFinished = True
Me.measureTimer.Stop()
Me.timeElapsed.Stop()
End If
End Sub
#End Region
#Region " Private Methods "
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Stops Time intervals and resets the elapsed and remaining time to zero.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Private Sub Reset()
Me.measureTimer.Stop()
Me.timeElapsed.Reset()
End Sub
#End Region
#Region " Event Handlers "
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Handles the <see cref="Timer.Tick"/> event of the <see cref="MeasureTimer"/> timer.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <param name="sender">
''' The source of the event.
''' </param>
'''
''' <param name="e">
''' The <see cref="EventArgs"/> instance containing the event data.
''' </param>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Private Sub MeasureTimer_Tick(ByVal sender As Object, ByVal e As Global.System.EventArgs) _
Handles measureTimer.Tick
Dim timeDiff As TimeSpan = (Me.timeRemaining - Me.timeElapsed.Elapsed)
' If finished...
If (timeDiff.TotalMilliseconds <= 0.0R) _
OrElse (Me.timeElapsed.ElapsedMilliseconds > DirectCast(Me.measureTimer.Tag, Double)) Then
Me.Reset()
Me.isFinished = True
If (Me.TimeUpdatedEvent IsNot Nothing) Then
Dim goal As TimeSpan = TimeSpan.FromMilliseconds(DirectCast(Me.measureTimer.Tag, Double))
RaiseEvent TimeUpdated(sender, New TimeMeasurerUpdatedEventArgs(goal, TimeSpan.FromMilliseconds(0.0R), goal))
End If
Else ' If not finished...
If (Me.TimeUpdatedEvent IsNot Nothing) Then
RaiseEvent TimeUpdated(sender, New TimeMeasurerUpdatedEventArgs(Me.timeElapsed.Elapsed,
timeDiff,
TimeSpan.FromMilliseconds(DirectCast(Me.measureTimer.Tag, Double))))
End If
End If
End Sub
#End Region
#Region " IDisposable Implementation "
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Flag to detect redundant calls when disposing.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Private isDisposed As Boolean = False
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Releases all the resources used by this instance.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Sub Dispose() Implements IDisposable.Dispose
Me.Dispose(isDisposing:=True)
GC.SuppressFinalize(obj:=Me)
End Sub
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
''' Releases unmanaged and, optionally, managed resources.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <param name="isDisposing">
''' <see langword="True"/> to release both managed and unmanaged resources;
''' <see langword="False"/> to release only unmanaged resources.
''' </param>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Private Sub Dispose(ByVal isDisposing As Boolean)
If (Not Me.isDisposed) AndAlso (isDisposing) Then
If (Me.measureTimer IsNot Nothing) Then
Me.measureTimer.Stop()
Me.measureTimer.Dispose()
Me.measureTimer = Nothing
End If
If (Me.TimeUpdatedEvent IsNot Nothing) Then
RemoveHandler Me.TimeUpdated, Me.TimeUpdatedEvent
End If
End If
Me.isDisposed = True
End Sub
#End Region
End Class
End Namespace
#End Region
+
Código (vbnet) [Seleccionar]
' ***********************************************************************
' Author : Elektro
' Modified : 12-December-2015
' ***********************************************************************
#Region " Option Statements "
Option Strict On
Option Explicit On
Option Infer Off
#End Region
#Region " TimeMeasurer State "
Namespace DateAndTime.Enums
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Specifies the current state of a <see cref="Types.TimeMeasurer"/> instance.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Public Enum TimeMeasurerState As Integer
''' <summary>
''' The <see cref="Types.TimeMeasurer"/> is running.
''' </summary>
Enabled = &H0I
''' <summary>
''' The <see cref="Types.TimeMeasurer"/> is paused.
''' </summary>
Paused = &H1I
''' <summary>
''' The <see cref="Types.TimeMeasurer"/> is fully stopped, it cannot be resumed.
''' </summary>
Disabled = &H2I
End Enum
End Namespace
#End Region
+
Código (vbnet) [Seleccionar]
' ***********************************************************************
' Author : Elektro
' Modified : 12-December-2015
' ***********************************************************************
#Region " Public Members Summary "
#Region " Constructors "
' New(TimeSpan, TimeSpan, TimeSpan)
#End Region
#Region " Properties "
' Elapsed As TimeSpan
' Remaining As TimeSpan
' Goal As TimeSpan
#End Region
#End Region
#Region " Option Statements "
Option Strict On
Option Explicit On
Option Infer Off
#End Region
#Region " Imports "
Imports System.ComponentModel
' Imports Elektro.Core.Types
#End Region
#Region " TimeMeasurerUpdated EventArgs "
Namespace DateAndTime.Types.EventArgs
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Contains the event-data of a <see cref="TimeMeasurer"/> event.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
<ImmutableObject(True)>
Public NotInheritable Class TimeMeasurerUpdatedEventArgs ' : Inherits AestheticEventArgs
#Region " Properties "
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets the elapsed time.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <value>
''' The elapsed time.
''' </value>
''' ----------------------------------------------------------------------------------------------------
Public ReadOnly Property Elapsed As TimeSpan
<DebuggerStepThrough>
Get
Return Me.elapsedB
End Get
End Property
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' ( Baking Field )
''' The elapsed time.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Private ReadOnly elapsedB As TimeSpan
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets the remaining time.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <value>
''' The remaining time.
''' </value>
''' ----------------------------------------------------------------------------------------------------
Public ReadOnly Property Remaining As TimeSpan
<DebuggerStepThrough>
Get
Return Me.remainingB
End Get
End Property
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' ( Baking Field )
''' The remaining time.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Private ReadOnly remainingB As TimeSpan
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets the goal time.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <value>
''' The goal time.
''' </value>
''' ----------------------------------------------------------------------------------------------------
Public ReadOnly Property Goal As TimeSpan
<DebuggerStepThrough>
Get
Return Me.goalB
End Get
End Property
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' ( Baking Field )
''' The goal time.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Private ReadOnly goalB As TimeSpan
#End Region
#Region " Constructors "
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Prevents a default instance of the <see cref="TimeMeasurerUpdatedEventArgs"/> class from being created.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
<DebuggerNonUserCode>
Private Sub New()
End Sub
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Initializes a new instance of the <see cref="TimeMeasurerUpdatedEventArgs"/> class.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <param name="elapsed">
''' The elapsed time.
''' </param>
'''
''' <param name="remaining">
''' The remaining time.
''' </param>
'''
''' <param name="goal">
''' The goal time.
''' </param>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Sub New(ByVal elapsed As TimeSpan,
ByVal remaining As TimeSpan,
ByVal goal As TimeSpan)
Me.elapsedB = elapsed
Me.remainingB = remaining
Me.goalB = goal
End Sub
#End Region
End Class
End Namespace
#End Region
Tendrías que editar las classes de arribas un poquito para eliminarle el código sobrante, es decir los espacios de nombres y los imports de la librería y creo que nada más.
El modo de empleo para implementarlo a modo de cuenta atrás, sería más o menos el siguiente:
Código (vbnet) [Seleccionar]
Public Class Form1 : Inherits Form
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' The <see cref="TimeMeasurer"/> instance that measure time intervals.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Private WithEvents countdown As New TimeMeasurer With {.UpdateInterval = 100}
' Label used to display the remaining time.
Private lblCountdown As Label
Private Sub Shown() Handles MyBase.Shown
Me.lblCountdown = Me.Label2
Me.countdown.Start(TimeSpan.FromMinutes(1.0R))
End Sub
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Handles the <see cref="TimeMeasurer.TimeUpdated"/> event of the countdown instance.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <param name="sender">
''' The source of the event.
''' </param>
'''
''' <param name="e">
''' The <see cref="TimeMeasurerUpdatedEventArgs"/> instance containing the event data.
''' </param>
''' ----------------------------------------------------------------------------------------------------
Private Sub Countdown_TimeUpdated(ByVal sender As Object, ByVal e As TimeMeasurerUpdatedEventArgs) _
Handles countdown.TimeUpdated
' Measure H:M:S:MS
Me.lblCountdown.Text = String.Format("{0:00}:{1:00}:{2:00}:{3:000}",
e.Remaining.Hours, e.Remaining.Minutes, e.Remaining.Seconds, e.Remaining.Milliseconds)
If (e.Elapsed.Subtract(e.Remaining) <= e.Goal) Then
Me.lblCountdown.Text = "Countdown Done!"
End If
End Sub
End Class
Si tienes cualquier duda al respecto del código, tan solo pregunta.
Saludos!.