C# 毫秒精确定时器#
我使用的是一个timer类(包装在C# 毫秒精确定时器#,c#,wpf,timer,C#,Wpf,Timer,我使用的是一个timer类(包装在System.Timers.timer),我想用它在WPF窗口中显示2分钟的倒计时,精确到每10毫秒一次。基本上,我希望以mm\\\:ss\\.ff格式显示一个字符串,该字符串每10毫秒更新一次。以下是我的课程: using System; using System.Timers; using Proj.Utilities.Extensions; namespace Proj.Framework { /// <summary> /// Counts
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();
}
}
}
使用系统;
使用系统计时器;
使用Proj.Utilities.Extensions;
命名空间项目框架
{
///
///墙时间倒计时,在指定的更新周期引发事件。
///
公共密封类毫秒计时器
{
私有只读时间跨度_initialTime;
专用只读计时器\u timerRep;
专用时间跨度(u timelexing);;
///
///倒计时中剩余的时间。
///
公共时间跨度剩余时间
{
获取{return\u timeRemaining;}
专用设备
{
_剩余时间=价值;
如果(\u timeRemaining\u timerRep.Enabled;
///
///每次更新周期结束时引发。
///
公共事件事件处理程序时间已更改;
///
///在整个倒计时结束时引发。
///
公共事件事件处理程序倒计时已过;
///
///创建一个新的倒计时。
///
///
///计时器应倒计时的时间量。
///
///
///倒计时计时器引发事件的时间段。
///
公共毫秒计时器(TimeSpan countDownTime,TimeSpan updatePeriod)
{
_初始时间=停机时间;
_timerRep=新定时器(10){AutoReset=true};
AttachEventHandlers();
}
私人无效附件
{
AttachedElapsedEventHandler();
AttachCountDownElapsedEventHandler();
}
私有无效附件DELAPSEDEVENTHANDLER()
{
_timerRep.Appeased+=一次失效;
}
私有void AttachCountDownElapsedEventHandler()附加
{
CountdownPeased+=OnCountdownPeased;
}
私有void InvokeTimeChanged()
{
//在Proj.Utilities.extensions中定义
InvokeFinStantiated(这是新的EventArgs());
}
私有void invokeCountDownAppeased()
{
InvokeFinStantiated(这是新的EventArgs());
}
私有无效失效(对象发送方,ElapsedEventArgs e)
{
剩余时间-=从毫秒开始的时间跨度(10);
InvokeTimeChanged();
}
私有void onCountDownAppeased(对象发送方,事件参数e)
{
停止();
}
///
///重新开始倒计时。
///
公共无效重新启动()
{
剩余时间=_初始时间;
_timerRep.Start();
InvokeTimeChanged();
}
///
///停止倒计时。
///
公共停车场()
{
_timerRep.Stop();
}
}
}
它是有效的,因为它做了我期望它做的事情,但是它太慢了。当我想让它从10秒开始倒计时时,大约需要15秒。最终目标是一门课,可以从2分钟开始倒计时,准确地说,分辨率为10毫秒。为什么这比它应该做的要长,我该怎么做才能让它工作得更好er?不要每次更改您的
剩余时间
-保留开始时间并与当前时间进行比较,以获得剩余时间
:
TimeRemaining = (DateTime.Now - _initialTime);
这样一来,您从
计时器中得到的任何错误都不会累积,但最终会趋于平衡。我曾经在多媒体计时器API周围编写了一个包装器,可以精确到1ms,请参见。未针对生产使用进行测试,因此请注意清空
然而,我觉得你的方法不正确。问问你自己,你是否真的需要精确的10毫秒计时来显示2分钟间隔的倒计时。你似乎把两个责任放在计时器上。保持准确的时间和定期引发事件。计时器只适用于这两种情况中的后一种。使用秒表
来保持时间准确。使用计时器从秒表中获取经过的时间,并定期更新显示。这样,无论计时器的准确度如何,时间都会保持准确。用户不会注意到计时器经过的时间有细微的偏差,也不会关心它是否每10或20毫秒更新一次。一些相关信息e“精确到每10毫秒”不适用于windows,我认为最小分辨率约为15毫秒,调度/抢占可以推得更高。您可能会看到结果(这就是为什么10秒看起来需要15秒)。如果您需要精确的10秒计时器(具有可变更新间隔)然后您需要两个计时器,一个用于整个期间,另一个用于更新,或者与日期/时间进行比较,但这也有解决问题。太好了!唯一的问题是它需要是var now=DateTime.now;
TimeRemaining=(\u initialTime-(now.TimeOfDay-\u start));
invoketimechaned()
这样类型就可以工作。\u started
是调用Restart()
方法的时间。谢谢!除了错误修复,DateTime提供的分辨率不足以满足用户的要求。@Atoms可能没有精确的规格,但大多数屏幕甚至不能显示每10毫秒(60Hz=~17MS)的更改因此,我怀疑10毫秒是一个硬性要求。