[英]Millisecond precise timer in C#
我正在使用一个计时器类( System.Timers.Timer
周围的包装器),我想用它在WPF窗口中显示2分钟的倒计时,精确到每10毫秒。 基本上,我想以mm\\\\:ss\\\\.ff
格式显示一个字符串,每10毫秒更新一次。 这是我的课程:
using System;
using System.Timers;
using Proj.Utilities.Extensions;
namespace Proj.Framework
{
/// <summary>
/// Counts down in wall time, raising events at a specified updated period.
/// </summary>
public sealed class MillisecondTimer
{
private readonly TimeSpan _initialTime;
private readonly Timer _timerRep;
private TimeSpan _timeRemaining;
/// <summary>
/// The time remaining in the countdown.
/// </summary>
public TimeSpan TimeRemaining
{
get { return _timeRemaining; }
private set
{
_timeRemaining = value;
if (_timeRemaining <= TimeSpan.Zero)
{
InvokeCountDownElapsed();
}
}
}
/// <summary>
/// True if the timer is currently counting down; false otherwise.
/// </summary>
public bool IsCountingDown => _timerRep.Enabled;
/// <summary>
/// Raised every time the update period elapses.
/// </summary>
public event EventHandler TimeChanged;
/// <summary>
/// Raised when the entire countdown elapses.
/// </summary>
public event EventHandler CountDownElapsed;
/// <summary>
/// Creates a new CountDownTimer.
/// </summary>
/// <param name="countDownTime">
/// The amount of time the timer should count down for.
/// </param>
/// <param name="updatePeriod">
/// The period with which the CountDownTimer should raise events.
/// </param>
public MillisecondTimer(TimeSpan countDownTime, TimeSpan updatePeriod)
{
_initialTime = countDownTime;
_timerRep = new Timer(10) { AutoReset = true };
AttachEventHandlers();
}
private void AttachEventHandlers()
{
AttachedElapsedEventHandler();
AttachCountDownElapsedEventHandler();
}
private void AttachedElapsedEventHandler()
{
_timerRep.Elapsed += OnElapsed;
}
private void AttachCountDownElapsedEventHandler()
{
CountDownElapsed += OnCountDownElapsed;
}
private void InvokeTimeChanged()
{
//Defined in Proj.Utilities.Extentions
TimeChanged.InvokeIfInstantiated(this, new EventArgs());
}
private void InvokeCountDownElapsed()
{
CountDownElapsed.InvokeIfInstantiated(this, new EventArgs());
}
private void OnElapsed(object sender, ElapsedEventArgs e)
{
TimeRemaining -= TimeSpan.FromMilliseconds(10);
InvokeTimeChanged();
}
private void OnCountDownElapsed(object sender, EventArgs e)
{
Stop();
}
/// <summary>
/// Restarts the countdown.
/// </summary>
public void Restart()
{
TimeRemaining = _initialTime;
_timerRep.Start();
InvokeTimeChanged();
}
/// <summary>
/// Stops the countdown.
/// </summary>
public void Stop()
{
_timerRep.Stop();
}
}
}
它起作用,因为它做了我期望它做的事情,但它最终太慢了。 当我希望它从10秒倒计时时,大约需要15秒。 最终目标是能够准确地从10分钟,10毫秒分辨率开始倒数。 为什么这需要的时间超过应有的时间,我能做些什么才能让它更好用呢?
不要每次都更改TimeRemaining
- 保持开始时间并与当前时间进行比较以获得TimeRemaining
:
TimeRemaining = (DateTime.Now - _initialTime);
这样,从Timer
获得的任何错误都不会累积,而是最终会均衡。
我曾经写过一个围绕多媒体计时器API的包装器,它可以准确地达到1毫秒,见这里 。 未经生产用途测试,因此请注意。
但是,您的方法似乎对我不正确。 问问自己是否真的需要准确的10 ms时间来显示2分钟间隔的倒计时。 你似乎在计时器上放了两个责任。 保持准确的时间并定期举办活动。 定时器仅适用于这两者中的后者。 使用Stopwatch
准确地保持时间。 使用计时器从秒表获取经过的时间并定期更新显示。 这样,无论计时器的准确性如何,时间都能保持准确。 用户不会注意到计时器经过多长时间的微小偏差,如果每10或20ms更新一次,则不会关心。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.