Reputation: 20110
I'm looking at how to pause a System.Timers.Timer
and I cannot figure out the proper way to pause it without resetting the timer.
How to pause it?
Upvotes: 7
Views: 14221
Reputation: 699
Based on previous comments from sveilleux2 and Tomerz, I improved the solution to implement IDisposable, allow multiple pause-resume calls, plus add Enabled and Paused properties.
public class PausableTimer: IDisposable
{
private Timer _timer;
private Stopwatch _stopWatch;
private bool _paused;
private double _remainingTimeBeforePause;
public event ElapsedEventHandler Elapsed;
public PausableTimer()
{
_stopWatch = new Stopwatch();
_timer = new Timer();
_timer.AutoReset = false;
_timer.Elapsed += (sender, arguments) =>
{
Elapsed?.Invoke(sender, arguments);
if (_timer != null && _timer.AutoReset)
{
_stopWatch.Restart();
}
};
}
public PausableTimer(double interval): this()
{
Interval = interval;
}
public bool AutoReset
{
get
{
return _timer.AutoReset;
}
set
{
_timer.AutoReset = value;
}
}
public bool Enabled
{
get
{
return _timer.Enabled;
}
set
{
_timer.Enabled = value;
}
}
public double Interval
{
get
{
return _timer.Interval;
}
set
{
_timer.Interval = value;
}
}
public bool Paused
{
get
{
return _paused;
}
}
public void Start()
{
_timer.Start();
_stopWatch.Restart();
}
public void Stop()
{
_timer.Stop();
_stopWatch.Stop();
}
public void Pause()
{
if (!_paused && _timer.Enabled)
{
_paused = true;
_stopWatch.Stop();
_timer.Stop();
_remainingTimeBeforePause = Math.Max(0, Interval - _stopWatch.ElapsedMilliseconds);
}
}
public void Resume()
{
if (_paused)
{
_paused = false;
if (_remainingTimeBeforePause > 0)
{
_timer.Interval = _remainingTimeBeforePause;
_timer.Start();
_stopWatch.Start();
}
}
}
bool _disposed = false;
public void Dispose()
{
if (_timer != null && !_disposed)
{
// Not thread safe...
_disposed = true;
_timer.Dispose();
_timer = null;
}
}
~PausableTimer()
{
Dispose();
}
}
Upvotes: 0
Reputation: 1512
Here is what I've been using. It's maybe not state-of-the-art accurate but works pretty good. At least, it's a good starting point for someone trying to pause/resume at timer.
public class PausableTimer
{
private Timer _timer;
private Stopwatch _stopWatch;
private bool _paused;
private double _interval;
private double _remainingTimeBeforePause;
public PausableTimer(double interval, ElapsedEventHandler handler)
{
_interval = interval;
_stopWatch = new Stopwatch();
_timer = new Timer(interval);
_timer.Elapsed += (sender, arguments) => {
if (handler != null)
{
if(_timer.AutoReset)
{
_stopWatch.Restart();
}
handler(sender, arguments);
}
};
_timer.AutoReset = false;
}
public bool AutoReset
{
get
{
return _timer.AutoReset;
}
set
{
_timer.AutoReset = value;
}
}
public void Start()
{
_timer.Start();
_stopWatch.Restart();
}
public void Stop()
{
_timer.Stop();
_stopWatch.Stop();
}
public void Pause()
{
if(!_paused && _timer.Enabled)
{
_stopWatch.Stop();
_timer.Stop();
_remainingTimeBeforePause = Math.Max(0, _interval - _stopWatch.ElapsedMilliseconds);
_paused = true;
}
}
public void Resume()
{
if(_paused)
{
_paused = false;
if(_remainingTimeBeforePause > 0)
{
_timer.Interval = _remainingTimeBeforePause;
_timer.Start();
}
}
}
}
Upvotes: 0
Reputation: 51
Create a timer like this:
System.Timers.Timer t = new System.Timers.Timer(1000)
t.Elapsed += new System.Timers.ElapsedEventHandler(timerEvent);
public void timerEvent(object source, System.Timers.ElapsedEventArgs e)
{
}
you can set this property to start or pause the timer execute the timeEvent:
Start:
t.Enabled = true
Pause:
t.Enabled = false
Upvotes: -1
Reputation: 20110
I got that for now, I'm sure it's not bulletproof so tell me what is wrong with it...
Public Class ImprovedTimer
Inherits System.Timers.Timer
Private _sw As System.Diagnostics.Stopwatch
Private _paused As Boolean
Private _originalInterval As Double
Private _intervalRemaining As Double?
Public ReadOnly Property IntervalRemaining() As Double?
Get
Return _intervalRemaining
End Get
End Property
Public ReadOnly Property Paused() As Boolean
Get
Return _paused
End Get
End Property
Public ReadOnly Property OriginalInterval() As Double
Get
Return _originalInterval
End Get
End Property
Public Sub Pause()
If Me.Enabled Then
_intervalRemaining = Me.Interval - _sw.ElapsedMilliseconds
_paused = True
resetStopWatch(False, False)
MyBase.Stop()
End If
End Sub
Public Sub [Resume]()
If _paused Then
Me.Interval = If(_intervalRemaining.HasValue, _intervalRemaining.Value, _originalInterval)
resetStopWatch(True, False)
MyBase.Start()
End If
End Sub
Public Overloads Property Enabled() As Boolean
Get
Return MyBase.Enabled
End Get
Set(ByVal value As Boolean)
MyBase.Enabled = value
resetStopWatch(MyBase.Enabled, True)
End Set
End Property
Public Overloads Sub Start()
resetStopWatch(True, True)
MyBase.Start()
End Sub
Public Overloads Sub [Stop]()
resetStopWatch(False, True)
MyBase.Stop()
End Sub
Public Overloads Property Interval() As Double
Get
Return MyBase.Interval
End Get
Set(ByVal value As Double)
MyBase.Interval = value
If Not _paused Then
_originalInterval = MyBase.Interval
End If
End Set
End Property
Private Sub resetStopWatch(ByVal startNew As Boolean, ByVal resetPause As Boolean)
If _sw IsNot Nothing Then
_sw.Stop()
_sw = Nothing
End If
If resetPause Then
If _paused Then
Me.Interval = _originalInterval
End If
_paused = False
_intervalRemaining = Nothing
End If
If startNew Then
_sw = System.Diagnostics.Stopwatch.StartNew
End If
End Sub
Private Sub ImprovedTimer_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
resetStopWatch(False, True)
End Sub
Private Sub ImprovedTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles Me.Elapsed
resetStopWatch(Me.AutoReset, True)
End Sub
End Class
Upvotes: 4
Reputation: 13363
You should follow the advice Shay Erlichmen gave. You'll need to save the time remaining when pausing, and continue from that point when the timer is resumed. As for what is wrong with your current code:
Me.Interval = Me.Interval - sw.ElapsedMilliseconds
The above code will make sure that next time you resume it will work as intended on the first tick, but on the continouos ticks you'll have Me.Interval - sw.ElapsedMilliseconds as the interval instead of the original set interval.
Upvotes: 0
Reputation: 31928
There is no Pause(), you can write one that on Pause():
on Resume():
If you write this class please post it in answer as it seem that many of us need that functionality out of the Timer class. :)
Upvotes: 9