正确的方法来暂停System.Timers.Timer?

时间:2022-07-13 20:38:33

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.

我正在研究如何暂停System.Timers.Timer,我无法找到正确的方法来暂停它而不重置计时器。

How to pause it?

怎么暂停呢?

5 个解决方案

#1


There is no Pause(), you can write one that on Pause():

没有Pause(),你可以在Pause()上写一个:

  1. Change(Timeout.Infinite, Timeout.Infinite)
  2. Save the calculate the amount of timer remaining.
  3. 保存计算剩余的计时器数量。

on Resume():

  1. Change(amount of timer remaining)
  2. 变化(剩余的计时器数量)

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. :)

如果您编写此类,请将其发布回答,因为我们中的许多人似乎都需要Timer类中的该功能。 :)

#2


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

#3


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:

你应该遵循Shay Erlichmen给出的建议。您需要在暂停时保存剩余时间,并在计时器恢复时从该点继续。至于你当前的代码有什么问题:

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.

上面的代码将确保您下次恢复时它将在第一个刻度上按预期工作,但在连续刻度上,您将有Me.Interval - sw.ElapsedMilliseconds作为间隔而不是原始设置间隔。

#4


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();
            }
        }
    }
}

#5


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:

你可以设置这个属性来启动或暂停定时器执行timeEvent:

Start:

    t.Enabled = true 

Pause:

    t.Enabled = false

#1


There is no Pause(), you can write one that on Pause():

没有Pause(),你可以在Pause()上写一个:

  1. Change(Timeout.Infinite, Timeout.Infinite)
  2. Save the calculate the amount of timer remaining.
  3. 保存计算剩余的计时器数量。

on Resume():

  1. Change(amount of timer remaining)
  2. 变化(剩余的计时器数量)

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. :)

如果您编写此类,请将其发布回答,因为我们中的许多人似乎都需要Timer类中的该功能。 :)

#2


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

#3


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:

你应该遵循Shay Erlichmen给出的建议。您需要在暂停时保存剩余时间,并在计时器恢复时从该点继续。至于你当前的代码有什么问题:

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.

上面的代码将确保您下次恢复时它将在第一个刻度上按预期工作,但在连续刻度上,您将有Me.Interval - sw.ElapsedMilliseconds作为间隔而不是原始设置间隔。

#4


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();
            }
        }
    }
}

#5


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:

你可以设置这个属性来启动或暂停定时器执行timeEvent:

Start:

    t.Enabled = true 

Pause:

    t.Enabled = false